@modelcontextprotocol/inspector 2.13.0 → 2.15.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 (34) hide show
  1. package/README.md +1 -1
  2. package/clients/cli/build/index.js +5481 -1847
  3. package/clients/mcpdo/build/mcp-bin.js +925 -186
  4. package/clients/mcpdo/build/mcpdod.js +2 -3
  5. package/clients/mcpdo/build/{server-BHuKGkMj.js → server-B-CUVIBj.js} +3544 -995
  6. package/clients/tui/build/index.js +2126 -570
  7. package/clients/web/build/index.js +459 -280
  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-BZ94R6fh.js +1599 -0
  12. package/clients/web/dist/assets/{index-dqp8Sd8W.css → index-tBehH5iF.css} +1 -1
  13. package/clients/web/dist/assets/{prism-light-BIhJtJkv.js → prism-light-Crps--E8.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/assets/worker-json-DEGsizKa.js +7859 -0
  27. package/clients/web/dist/fonts/Fredoka-OFL.txt +93 -0
  28. package/clients/web/dist/fonts/RobotoMono-OFL.txt +93 -0
  29. package/clients/web/dist/index.html +2 -5
  30. package/clients/web/static/sandbox_proxy.html +177 -6
  31. package/package.json +8 -4
  32. package/skills/mcpdo/SKILL.md +63 -2
  33. package/clients/web/dist/assets/index-BqEbhCDX.js +0 -1587
  34. package/clients/web/dist/assets/worker-json-8CDXFfik.js +0 -1631
@@ -31,7 +31,10 @@ import { runtimeCodecFromStandardSchema, taskId, toJsonValue } from "@modelconte
31
31
  import { CallToolResultSchema, ElicitResultSchema, EmptyResultSchema, GetPromptResultSchema, ListPromptsResultSchema, ListResourceTemplatesResultSchema, ListResourcesResultSchema, ListToolsResultSchema, NotificationSchema, OAuthClientInformationSchema, OAuthMetadataSchema, OAuthTokensSchema, OpenIdProviderDiscoveryMetadataSchema, ProgressTokenSchema, PromptSchema, ReadResourceResultSchema, RequestMetaSchema, ResourceSchema, ResourceTemplateSchema, TaskStatusNotificationSchema, ToolSchema } from "@modelcontextprotocol/core";
32
32
  import { TASKS_EXTENSION_ID_V2 as TASKS_EXTENSION_KEY } from "@modelcontextprotocol/ext-tasks/core/v2";
33
33
  import { RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/app-bridge";
34
- import { AjvJsonSchemaValidator } from "@modelcontextprotocol/client/validators/ajv";
34
+ import Ajv from "ajv";
35
+ import { Ajv2019 } from "ajv/dist/2019.js";
36
+ import { Ajv2020 } from "ajv/dist/2020.js";
37
+ import { addFormats } from "@modelcontextprotocol/client/validators/ajv";
35
38
  import { createServer } from "node:http";
36
39
  import pino from "pino";
37
40
  import open from "open";
@@ -40,15 +43,14 @@ import os from "node:os";
40
43
  import process$1 from "node:process";
41
44
  import tty from "node:tty";
42
45
  import { isDeepStrictEqual } from "node:util";
43
- //#region ../../core/storage/store-serialize.ts
46
+ // ../../core/storage/store-serialize.ts
44
47
  function serializeStore(data) {
45
48
  return JSON.stringify(data, null, 2);
46
49
  }
47
50
  function parseStore(raw) {
48
51
  return JSON.parse(raw);
49
52
  }
50
- //#endregion
51
- //#region ../../core/storage/store-io.ts
53
+ // ../../core/storage/store-io.ts
52
54
  function getDefaultStorageDir() {
53
55
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
54
56
  return path$1.join(homeDir, ".mcp-inspector", "storage");
@@ -94,8 +96,7 @@ async function deleteStoreFile(filePath) {
94
96
  if (error.code !== "ENOENT") throw error;
95
97
  }
96
98
  }
97
- //#endregion
98
- //#region ../../core/mcp/types.ts
99
+ // ../../core/mcp/types.ts
99
100
  function isTerminalStatus(status) {
100
101
  return status === "disconnected" || status === "error";
101
102
  }
@@ -133,8 +134,7 @@ function eraToVersionNegotiation(era) {
133
134
  case "legacy": return { mode: "legacy" };
134
135
  }
135
136
  }
136
- //#endregion
137
- //#region ../../core/extension/skills/schemas.ts
137
+ // ../../core/extension/skills/schemas.ts
138
138
  const CACHE_FIELDS = {
139
139
  ttlMs: ReadResourceDirectoryResultSchema.shape.ttlMs,
140
140
  cacheScope: SkillCacheScopeSchema
@@ -167,8 +167,7 @@ const DirectoryReadResultSchema = ReadResourceDirectoryResultSchema.partial({
167
167
  ttlMs: true,
168
168
  cacheScope: true
169
169
  });
170
- //#endregion
171
- //#region ../../core/extension/skills/sha256.ts
170
+ // ../../core/extension/skills/sha256.ts
172
171
  const K = new Uint32Array([
173
172
  1116352408,
174
173
  1899447441,
@@ -294,8 +293,7 @@ function sha256Bytes(bytes) {
294
293
  for (let i = 0; i < 8; i += 1) out.setUint32(i * 4, h[i]);
295
294
  return digest;
296
295
  }
297
- //#endregion
298
- //#region ../../core/extension/skills/skillFile.ts
296
+ // ../../core/extension/skills/skillFile.ts
299
297
  function splitSkillFile(text) {
300
298
  if (!/^---[ \t]*\r?\n/.test(text)) return { body: text };
301
299
  const rest = text.slice(text.indexOf("\n") + 1);
@@ -343,8 +341,7 @@ function parseSkillFrontmatter(yamlText) {
343
341
  if (graphError) return { error: graphError };
344
342
  return { fields: parsed };
345
343
  }
346
- //#endregion
347
- //#region ../../core/extension/skills/conformance.ts
344
+ // ../../core/extension/skills/conformance.ts
348
345
  const SKILL_MAX_RESOURCE_ENTRIES = SKILL_LIMITS.files;
349
346
  const SKILL_MAX_TOTAL_BYTES = SKILL_LIMITS.bytes;
350
347
  const SKILL_MAX_CATALOG_BYTES = 67108864;
@@ -702,13 +699,11 @@ function checkSkillNameCollisions(entries) {
702
699
  }
703
700
  return issues;
704
701
  }
705
- //#endregion
706
- //#region ../../core/auth/secret-fields.ts
702
+ // ../../core/auth/secret-fields.ts
707
703
  const SECRET_FIELD_OAUTH_CLIENT_SECRET = "oauth-client-secret";
708
704
  const SECRET_FIELD_IDP_CLIENT_SECRET = "idp-client-secret";
709
705
  const envSecretField = (envKey) => `env:${envKey}`;
710
- //#endregion
711
- //#region ../../core/json/localRefs.ts
706
+ // ../../core/json/localRefs.ts
712
707
  const SUBSCHEMA_KEYWORDS$1 = /* @__PURE__ */ new Set([
713
708
  "items",
714
709
  "contains",
@@ -863,8 +858,7 @@ function inlineLocalRefs(schema) {
863
858
  cache.set(schema, resolved);
864
859
  return resolved;
865
860
  }
866
- //#endregion
867
- //#region ../../core/json/nullableUnion.ts
861
+ // ../../core/json/nullableUnion.ts
868
862
  const RENDERABLE_TYPES = [
869
863
  "string",
870
864
  "number",
@@ -1017,8 +1011,7 @@ function normalizeNullableUnion(schema) {
1017
1011
  }
1018
1012
  return schema;
1019
1013
  }
1020
- //#endregion
1021
- //#region ../../core/json/rootUnion.ts
1014
+ // ../../core/json/rootUnion.ts
1022
1015
  function membersOf(value) {
1023
1016
  return Array.isArray(value) ? value : [];
1024
1017
  }
@@ -1238,8 +1231,7 @@ function narrowBySuppliedNames(branches, candidates, suppliedNames) {
1238
1231
  const named = new Set(suppliedNames.map((name) => exclusiveTo.get(name)).filter((index) => index !== void 0 && index >= 0));
1239
1232
  return named.size === 1 ? [...named][0] : null;
1240
1233
  }
1241
- //#endregion
1242
- //#region ../../core/json/jsonUtils.ts
1234
+ // ../../core/json/jsonUtils.ts
1243
1235
  function isSerializableJson(value) {
1244
1236
  if (value === null) return true;
1245
1237
  switch (typeof value) {
@@ -1340,8 +1332,7 @@ function convertPromptArguments(args) {
1340
1332
  else stringArgs[key] = JSON.stringify(value);
1341
1333
  return stringArgs;
1342
1334
  }
1343
- //#endregion
1344
- //#region ../../core/mcp/serverList.ts
1335
+ // ../../core/mcp/serverList.ts
1345
1336
  const VALID_SERVER_TYPES = /* @__PURE__ */ new Set([
1346
1337
  "stdio",
1347
1338
  "sse",
@@ -1607,8 +1598,15 @@ function expectedSecretFields(stored) {
1607
1598
  if (isStdioStored(stored) && stored.env) for (const k of Object.keys(stored.env)) fields.push(envSecretField(k));
1608
1599
  return fields;
1609
1600
  }
1610
- //#endregion
1611
- //#region ../../core/storage/own-entry.ts
1601
+ function adHocServerName(config) {
1602
+ if (config.type === "sse" || config.type === "streamable-http") try {
1603
+ return new URL(config.url).host || "server";
1604
+ } catch {
1605
+ return "server";
1606
+ }
1607
+ return config.command?.split(/[\\/]/).pop() || "server";
1608
+ }
1609
+ // ../../core/storage/own-entry.ts
1612
1610
  function setOwnEntry(map, key, value) {
1613
1611
  Object.defineProperty(map, key, {
1614
1612
  value,
@@ -1620,8 +1618,7 @@ function setOwnEntry(map, key, value) {
1620
1618
  function getOwnEntry(map, key) {
1621
1619
  return map !== void 0 && Object.hasOwn(map, key) ? map[key] : void 0;
1622
1620
  }
1623
- //#endregion
1624
- //#region ../../core/mcp/node/config.ts
1621
+ // ../../core/mcp/node/config.ts
1625
1622
  function parseKeyValuePair(value, previous = {}) {
1626
1623
  const parts = value.split("=");
1627
1624
  const key = parts[0] ?? "";
@@ -1812,8 +1809,7 @@ function resolveServerConfigs(options, mode) {
1812
1809
  }
1813
1810
  return [];
1814
1811
  }
1815
- //#endregion
1816
- //#region ../../core/auth/secret-storage-info.ts
1812
+ // ../../core/auth/secret-storage-info.ts
1817
1813
  function secretStorageLabel(info) {
1818
1814
  switch (info.kind) {
1819
1815
  case "keyring": return "OS keychain";
@@ -1840,8 +1836,7 @@ function secretStorageSummary(info) {
1840
1836
  if (info.reason === "fallback") parts.push("— fell back from the OS keychain");
1841
1837
  return parts.join(" ");
1842
1838
  }
1843
- //#endregion
1844
- //#region ../../core/auth/node/secret-store.ts
1839
+ // ../../core/auth/node/secret-store.ts
1845
1840
  const SERVICE_NAME = "mcp-inspector";
1846
1841
  let keyringLoad;
1847
1842
  var KeyringModuleShapeError = class extends Error {
@@ -2061,8 +2056,7 @@ var SessionSecretStore = class extends InMemorySecretStore {
2061
2056
  return false;
2062
2057
  }
2063
2058
  };
2064
- //#endregion
2065
- //#region ../../core/auth/node/file-lock.ts
2059
+ // ../../core/auth/node/file-lock.ts
2066
2060
  const STALE_MS = 1e4;
2067
2061
  const RETRY = {
2068
2062
  retries: 20,
@@ -2194,8 +2188,7 @@ async function withSecretFileLock(filePath, fn) {
2194
2188
  await release();
2195
2189
  }
2196
2190
  }
2197
- //#endregion
2198
- //#region ../../core/auth/node/file-secret-store.ts
2191
+ // ../../core/auth/node/file-secret-store.ts
2199
2192
  const scrypt = (passphrase, salt, keylen, options) => new Promise((resolve, reject) => {
2200
2193
  crypto$1.scrypt(passphrase, salt, keylen, options, (err, key) => {
2201
2194
  /* v8 ignore next -- @preserve: node validates the cost parameters
@@ -2603,8 +2596,7 @@ async function readSecretFilePermissions(filePath) {
2603
2596
  };
2604
2597
  }
2605
2598
  }
2606
- //#endregion
2607
- //#region ../../core/auth/node/secret-store-selection.ts
2599
+ // ../../core/auth/node/secret-store-selection.ts
2608
2600
  const SECRET_STORE_ENV = "MCP_INSPECTOR_SECRET_STORE";
2609
2601
  const SECRET_FILE_ENV = "MCP_INSPECTOR_SECRET_FILE";
2610
2602
  const STORAGE_DIR_ENV = "MCP_STORAGE_DIR";
@@ -2911,8 +2903,7 @@ function defaultSecretStore() {
2911
2903
  async function resolveConcreteSecretStore(store) {
2912
2904
  return store instanceof DeferredSecretStore ? (await resolveSecretStore()).store : store;
2913
2905
  }
2914
- //#endregion
2915
- //#region ../../core/mcp/node/server-secrets.ts
2906
+ // ../../core/mcp/node/server-secrets.ts
2916
2907
  async function rehydrateMcpConfigFromKeychain(config, secretStore) {
2917
2908
  const entries = Object.entries(config.mcpServers);
2918
2909
  const secrets = await secretStoreGetMany(secretStore, entries.map(([serverId, stored]) => ({
@@ -2923,8 +2914,7 @@ async function rehydrateMcpConfigFromKeychain(config, secretStore) {
2923
2914
  for (const [id, stored] of entries) out.mcpServers[id] = mergeSecretsIntoStored(stored, secrets[id] ?? {});
2924
2915
  return out;
2925
2916
  }
2926
- //#endregion
2927
- //#region ../../core/mcp/node/servers.ts
2917
+ // ../../core/mcp/node/servers.ts
2928
2918
  function headersToServerSettings(headers) {
2929
2919
  if (!headers || Object.keys(headers).length === 0) return;
2930
2920
  return {
@@ -2996,13 +2986,13 @@ async function loadServerEntries(serverOptions) {
2996
2986
  }
2997
2987
  const configs = resolveServerConfigs(serverOptions, "multi");
2998
2988
  if (configs.length === 0) throw new Error("At least one server is required. Use --catalog/--config <path> or an ad-hoc target (command/URL).");
2999
- return { default: {
3000
- config: configs[0],
2989
+ const config = configs[0];
2990
+ return { [adHocServerName(config)]: {
2991
+ config,
3001
2992
  settings: mergeSettings(void 0, serverOptions)
3002
2993
  } };
3003
2994
  }
3004
- //#endregion
3005
- //#region ../../core/mcp/config.ts
2995
+ // ../../core/mcp/config.ts
3006
2996
  function getServerType(config) {
3007
2997
  if (!("type" in config) || config.type === void 0) return "stdio";
3008
2998
  const type = config.type;
@@ -3011,8 +3001,7 @@ function getServerType(config) {
3011
3001
  if (type === "streamable-http") return "streamable-http";
3012
3002
  throw new Error(`Invalid server type: ${type}. Valid types are: stdio, sse, streamable-http`);
3013
3003
  }
3014
- //#endregion
3015
- //#region ../../core/mcp/fetchTracking.ts
3004
+ // ../../core/mcp/fetchTracking.ts
3016
3005
  const SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
3017
3006
  "authorization",
3018
3007
  "cookie",
@@ -3065,6 +3054,37 @@ function redactUrlQuery(url) {
3065
3054
  }
3066
3055
  }
3067
3056
  const EMBEDDED_URL_PATTERN = /\bhttps?:\/\/(?:(?!https?:\/\/)[^\s"<>])+/gi;
3057
+ function newUrlScan() {
3058
+ return {
3059
+ phase: "path",
3060
+ name: "",
3061
+ inValue: false,
3062
+ sensitive: false,
3063
+ endsWithEquals: false
3064
+ };
3065
+ }
3066
+ function advanceUrlScan(scan, piece, sensitiveNames) {
3067
+ for (const char of piece) {
3068
+ if (scan.phase === "fragment") break;
3069
+ if (char === "#") scan.phase = "fragment";
3070
+ else if (scan.phase === "path") {
3071
+ if (char === "?") scan.phase = "query";
3072
+ } else if (char === "&") {
3073
+ scan.name = "";
3074
+ scan.inValue = false;
3075
+ scan.sensitive = false;
3076
+ } else if (!scan.inValue) {
3077
+ if (char === "=") {
3078
+ scan.inValue = true;
3079
+ scan.sensitive = [...new URLSearchParams(`&${scan.name}=`).keys()].some((key) => sensitiveNames.has(key.toLowerCase()));
3080
+ } else scan.name += char;
3081
+ }
3082
+ }
3083
+ scan.endsWithEquals = scan.phase === "query" && scan.inValue && piece.endsWith("=");
3084
+ }
3085
+ function opensSensitiveValue(scan) {
3086
+ return scan.endsWithEquals && scan.sensitive;
3087
+ }
3068
3088
  const TRAILING_PUNCTUATION = /* @__PURE__ */ new Set([
3069
3089
  ".",
3070
3090
  ",",
@@ -3082,10 +3102,37 @@ function trailingPunctuationStart(match) {
3082
3102
  return end;
3083
3103
  }
3084
3104
  function redactUrlsInText(text) {
3085
- return text.replace(EMBEDDED_URL_PATTERN, (match) => {
3086
- const end = trailingPunctuationStart(match);
3087
- return redactUrlQuery(match.slice(0, end)) + match.slice(end);
3088
- });
3105
+ return mapUrlsInText(text, redactUrlQuery);
3106
+ }
3107
+ function mapUrlsInText(text, redact, sensitiveNames = SENSITIVE_BODY_FIELDS) {
3108
+ let out = "";
3109
+ let copied = 0;
3110
+ let pieces = [];
3111
+ let scan = newUrlScan();
3112
+ const flush = () => {
3113
+ if (pieces.length === 0) return;
3114
+ const joined = pieces.join("");
3115
+ const end = trailingPunctuationStart(joined);
3116
+ const redacted = redact(joined.slice(0, end));
3117
+ out += pieces.length > 1 && redacted === joined.slice(0, end) ? pieces.map((piece) => redactMatch(piece, redact)).join("") : redacted + joined.slice(end);
3118
+ };
3119
+ for (const match of text.matchAll(EMBEDDED_URL_PATTERN)) {
3120
+ if (match.index !== copied || !opensSensitiveValue(scan)) {
3121
+ flush();
3122
+ out += text.slice(copied, match.index);
3123
+ pieces = [];
3124
+ scan = newUrlScan();
3125
+ }
3126
+ pieces.push(match[0]);
3127
+ advanceUrlScan(scan, match[0], sensitiveNames);
3128
+ copied = match.index + match[0].length;
3129
+ }
3130
+ flush();
3131
+ return out + text.slice(copied);
3132
+ }
3133
+ function redactMatch(match, redact) {
3134
+ const end = trailingPunctuationStart(match);
3135
+ return redact(match.slice(0, end)) + match.slice(end);
3089
3136
  }
3090
3137
  function redactJsonValue(value) {
3091
3138
  if (Array.isArray(value)) return value.map(redactJsonValue);
@@ -3144,14 +3191,15 @@ function isLongLivedStreamResponse(method, contentType) {
3144
3191
  }
3145
3192
  const CHALLENGE_BODY_MAX_BYTES = 65536;
3146
3193
  const CHALLENGE_BODY_READ_MS = 2e3;
3194
+ const TRACKED_BODY_MAX_BYTES = 1048576;
3147
3195
  const TRUNCATED_BODY_SUFFIX = "\n[truncated]";
3148
3196
  const WITHHELD_TRUNCATED_JSON_BODY = "[truncated JSON body withheld: an incomplete body cannot be redacted]";
3149
- function recordableChallengeBody(read, contentType) {
3197
+ function recordableBody(read, contentType) {
3150
3198
  if (!read.truncated) return redactBody(read.text, contentType);
3151
3199
  if ((contentType ?? "").toLowerCase().includes("json") || /^\s*[{[]/.test(read.text)) return WITHHELD_TRUNCATED_JSON_BODY;
3152
3200
  return redactBody(read.text, contentType) + TRUNCATED_BODY_SUFFIX;
3153
3201
  }
3154
- async function readChallengeBody(response) {
3202
+ async function readCappedBody(response, maxBytes, timeoutMs) {
3155
3203
  let reader;
3156
3204
  try {
3157
3205
  const body = response.clone().body;
@@ -3165,20 +3213,23 @@ async function readChallengeBody(response) {
3165
3213
  let text = "";
3166
3214
  let bytes = 0;
3167
3215
  let timer;
3168
- const deadline = new Promise((resolve) => {
3169
- timer = setTimeout(() => resolve("timeout"), CHALLENGE_BODY_READ_MS);
3216
+ const deadline = timeoutMs === void 0 ? void 0 : new Promise((resolve) => {
3217
+ timer = setTimeout(() => resolve("timeout"), timeoutMs);
3170
3218
  });
3171
3219
  try {
3172
- while (bytes < CHALLENGE_BODY_MAX_BYTES) {
3173
- const next = await Promise.race([reader.read(), deadline]);
3220
+ for (;;) {
3221
+ const next = await (deadline ? Promise.race([reader.read(), deadline]) : reader.read());
3174
3222
  if (next === "timeout") break;
3175
3223
  if (next.done) return {
3176
3224
  text: text + decoder.decode(),
3177
3225
  truncated: false
3178
3226
  };
3179
- const chunk = next.value.subarray(0, CHALLENGE_BODY_MAX_BYTES - bytes);
3227
+ if (next.value.byteLength === 0) continue;
3228
+ if (bytes >= maxBytes) break;
3229
+ const chunk = next.value.subarray(0, maxBytes - bytes);
3180
3230
  bytes += chunk.byteLength;
3181
3231
  text += decoder.decode(chunk, { stream: true });
3232
+ if (chunk.byteLength < next.value.byteLength) break;
3182
3233
  }
3183
3234
  reader.cancel().catch(() => {});
3184
3235
  return {
@@ -3191,6 +3242,9 @@ async function readChallengeBody(response) {
3191
3242
  clearTimeout(timer);
3192
3243
  }
3193
3244
  }
3245
+ function readChallengeBody(response) {
3246
+ return readCappedBody(response, CHALLENGE_BODY_MAX_BYTES, CHALLENGE_BODY_READ_MS);
3247
+ }
3194
3248
  function longLivedStreamFraming(contentType) {
3195
3249
  return contentType?.toLowerCase().includes("application/x-ndjson") ? "ndjson" : "sse";
3196
3250
  }
@@ -3356,7 +3410,7 @@ function createFetchTracker(baseFetch, callbacks) {
3356
3410
  };
3357
3411
  if ((responseStatus === 401 || responseStatus === 403) && response.body && !response.bodyUsed) {
3358
3412
  const read = await readChallengeBody(response);
3359
- entry.responseBody = read === void 0 ? void 0 : recordableChallengeBody(read, response.headers.get("content-type"));
3413
+ entry.responseBody = read === void 0 ? void 0 : recordableBody(read, response.headers.get("content-type"));
3360
3414
  callbacks.trackRequest?.(entry);
3361
3415
  return response;
3362
3416
  }
@@ -3364,17 +3418,17 @@ function createFetchTracker(baseFetch, callbacks) {
3364
3418
  if (isLongLivedStream && response.body && !response.bodyUsed) watchLongLivedStream(response, id, longLivedStreamFraming(response.headers.get("content-type")), callbacks);
3365
3419
  if (!isLongLivedStream && response.body && !response.bodyUsed) {
3366
3420
  const responseContentType = response.headers.get("content-type");
3367
- try {
3368
- response.clone().text().then((body) => {
3369
- callbacks.updateResponseBody?.(id, redactBody(body, responseContentType) ?? body);
3370
- }).catch(() => {});
3371
- } catch {}
3421
+ readCappedBody(response, TRACKED_BODY_MAX_BYTES).then((read) => {
3422
+ if (read === void 0) return;
3423
+ try {
3424
+ callbacks.updateResponseBody?.(id, recordableBody(read, responseContentType));
3425
+ } catch {}
3426
+ });
3372
3427
  }
3373
3428
  return response;
3374
3429
  };
3375
3430
  }
3376
- //#endregion
3377
- //#region ../../core/auth/utils.ts
3431
+ // ../../core/auth/utils.ts
3378
3432
  function parseHttpUrl(value, label) {
3379
3433
  const trimmed = value.trim();
3380
3434
  try {
@@ -3453,8 +3507,7 @@ function isUnauthorizedErrorDeep(err, seen) {
3453
3507
  if (data !== null && typeof data === "object" && "cause" in data && isUnauthorizedErrorDeep(data.cause, seen)) return true;
3454
3508
  return false;
3455
3509
  }
3456
- //#endregion
3457
- //#region ../../core/auth/challenge.ts
3510
+ // ../../core/auth/challenge.ts
3458
3511
  const EMA_STEP_UP_PENDING_URL = new URL("mcp-inspector:ema-step-up");
3459
3512
  var AuthChallengeError = class extends Error {
3460
3513
  authChallenge;
@@ -3600,8 +3653,7 @@ function isAuthChallengeError(err) {
3600
3653
  const wwwAuthenticate = authChallenge?.raw?.wwwAuthenticate ?? err.wwwAuthenticate ?? err.headers?.get?.("WWW-Authenticate") ?? void 0;
3601
3654
  return wwwAuthenticate !== void 0 && wwwAuthenticate.length > 0;
3602
3655
  }
3603
- //#endregion
3604
- //#region ../../core/mcp/node/authChallengeFetch.ts
3656
+ // ../../core/mcp/node/authChallengeFetch.ts
3605
3657
  function createAuthChallengeInterceptFetch(baseFetch) {
3606
3658
  return async (input, init) => {
3607
3659
  const response = await baseFetch(input, init);
@@ -3622,8 +3674,7 @@ function createAuthChallengeObserverFetch(baseFetch, onChallenge) {
3622
3674
  return response;
3623
3675
  };
3624
3676
  }
3625
- //#endregion
3626
- //#region ../../core/mcp/node/proxyFetch.ts
3677
+ // ../../core/mcp/node/proxyFetch.ts
3627
3678
  function asUndiciInit(init) {
3628
3679
  return init;
3629
3680
  }
@@ -3713,8 +3764,7 @@ function createProxyFetch() {
3713
3764
  return (await loadedProxiedFetch)(input, init);
3714
3765
  };
3715
3766
  }
3716
- //#endregion
3717
- //#region ../../core/auth/requestTimeout.ts
3767
+ // ../../core/auth/requestTimeout.ts
3718
3768
  const DEFAULT_OAUTH_REQUEST_TIMEOUT_MS = 3e4;
3719
3769
  var OAuthRequestTimeoutError = class extends Error {
3720
3770
  url;
@@ -3842,11 +3892,39 @@ function withOAuthRequestTimeout(fetchFn, timeoutMs = DEFAULT_OAUTH_REQUEST_TIME
3842
3892
  }
3843
3893
  };
3844
3894
  }
3845
- //#endregion
3846
- //#region ../../core/mcp/node/fetchGuard.ts
3895
+ // ../../core/auth/fetchRefusal.ts
3847
3896
  var FetchTargetError = class extends Error {
3848
3897
  name = "FetchTargetError";
3898
+ url;
3899
+ constructor(message, url) {
3900
+ super(message);
3901
+ if (url !== void 0) this.url = url;
3902
+ }
3849
3903
  };
3904
+ function findFetchTargetError(err) {
3905
+ let current = err;
3906
+ for (let depth = 0; depth < 8 && current instanceof Error; depth++) {
3907
+ if (current instanceof FetchTargetError) return current;
3908
+ current = current.cause;
3909
+ }
3910
+ }
3911
+ function formatFetchRefusal(refusal) {
3912
+ return `Refused to fetch ${refusal.url}: ${refusal.reason}`;
3913
+ }
3914
+ function withFetchRefusalReporting(base, onRefusal) {
3915
+ return async (input, init) => {
3916
+ try {
3917
+ return await base(input, init);
3918
+ } catch (err) {
3919
+ const refused = findFetchTargetError(err);
3920
+ if (refused) onRefusal({
3921
+ url: redactUrlQuery(refused.url ?? requestUrlOf$2(input)),
3922
+ reason: refused.message
3923
+ });
3924
+ throw err;
3925
+ }
3926
+ };
3927
+ }
3850
3928
  const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
3851
3929
  301,
3852
3930
  302,
@@ -3855,11 +3933,12 @@ const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
3855
3933
  308
3856
3934
  ]);
3857
3935
  const resolveWithSystemDns = async (hostname) => (await lookup(hostname, { all: true })).map((r) => r.address);
3936
+ const METADATA_IPV4_ADDRESSES = /* @__PURE__ */ new Set(["100.100.100.200", "192.0.0.192"]);
3858
3937
  function isBlockedAddress(ip) {
3859
3938
  const kind = isIP(ip);
3860
3939
  if (kind === 4) {
3861
3940
  const [a, b] = ip.split(".").map(Number);
3862
- return a === 169 && b === 254;
3941
+ return a === 169 && b === 254 || METADATA_IPV4_ADDRESSES.has(ip);
3863
3942
  }
3864
3943
  if (kind !== 6) return false;
3865
3944
  const addr = ip.toLowerCase();
@@ -4016,27 +4095,35 @@ async function guardedFetch(url, init, options = {}) {
4016
4095
  headers: init.headers
4017
4096
  };
4018
4097
  for (let hop = 0; hop <= 5; hop++) {
4019
- await assertAllowedTarget(request.url, resolveHost, viaProxy, init.signal);
4020
- const res = await fetchFn(request.url.href, {
4021
- method: request.method,
4022
- headers: new Headers(request.headers),
4023
- body: request.body,
4024
- signal: init.signal,
4025
- redirect: "manual"
4026
- });
4098
+ let res;
4099
+ try {
4100
+ await assertAllowedTarget(request.url, resolveHost, viaProxy, init.signal);
4101
+ res = await fetchFn(request.url.href, {
4102
+ method: request.method,
4103
+ headers: new Headers(request.headers),
4104
+ body: request.body,
4105
+ signal: init.signal,
4106
+ redirect: "manual"
4107
+ });
4108
+ } catch (err) {
4109
+ stampRefusedUrl(err, request.url);
4110
+ throw err;
4111
+ }
4027
4112
  const location = res.headers.get("location");
4028
4113
  if (!REDIRECT_STATUSES.has(res.status) || location === null) return res;
4029
4114
  res.body?.cancel().catch(() => {});
4030
- request = nextRedirectRequest(request, res.status, location);
4115
+ try {
4116
+ request = nextRedirectRequest(request, res.status, location);
4117
+ } catch (err) {
4118
+ stampRefusedUrl(err, request.url);
4119
+ throw err;
4120
+ }
4031
4121
  }
4032
- throw new FetchTargetError(`Refusing to follow more than 5 redirects`);
4122
+ throw new FetchTargetError(`Refusing to follow more than 5 redirects`, request.url.href);
4033
4123
  }
4034
- function findFetchTargetError(err) {
4035
- let current = err;
4036
- for (let depth = 0; depth < 8 && current instanceof Error; depth++) {
4037
- if (current instanceof FetchTargetError) return current;
4038
- current = current.cause;
4039
- }
4124
+ function stampRefusedUrl(err, url) {
4125
+ const refused = findFetchTargetError(err);
4126
+ if (refused && refused.url === void 0) refused.url = url.href;
4040
4127
  }
4041
4128
  async function bodyText(input, init) {
4042
4129
  const body = init?.body !== void 0 ? init.body : input instanceof Request && input.body !== null ? await input.clone().text() : void 0;
@@ -4063,8 +4150,7 @@ function createGuardedFetch(options = {}) {
4063
4150
  }
4064
4151
  };
4065
4152
  }
4066
- //#endregion
4067
- //#region ../../core/auth/routeOAuthRequests.ts
4153
+ // ../../core/auth/routeOAuthRequests.ts
4068
4154
  function isJsonRpcMessage(value) {
4069
4155
  return typeof value === "object" && value !== null && value.jsonrpc === "2.0";
4070
4156
  }
@@ -4088,8 +4174,7 @@ function isMcpShapedRequest(input, init) {
4088
4174
  function routeOAuthRequests(mcpFetch, oauthFetch, isMcpEndpoint) {
4089
4175
  return (input, init) => isMcpShapedRequest(input, init) && isMcpEndpoint(requestUrlOf$2(input), requestHeadersOf(input, init)) ? mcpFetch(input, init) : oauthFetch(input, init);
4090
4176
  }
4091
- //#endregion
4092
- //#region ../../core/mcp/node/notificationHeadersFetch.ts
4177
+ // ../../core/mcp/node/notificationHeadersFetch.ts
4093
4178
  function createNotificationHeadersFetch(baseFetch) {
4094
4179
  return (input, init) => {
4095
4180
  const method = modernNotificationMethod(init);
@@ -4125,8 +4210,7 @@ function modernNotificationMethod(init) {
4125
4210
  function isRecord$4(value) {
4126
4211
  return typeof value === "object" && value !== null && !Array.isArray(value);
4127
4212
  }
4128
- //#endregion
4129
- //#region ../../core/mcp/node/suppressNotificationStreamFetch.ts
4213
+ // ../../core/mcp/node/suppressNotificationStreamFetch.ts
4130
4214
  function createSuppressNotificationStreamFetch(baseFetch, endpoint) {
4131
4215
  return async (input, init) => {
4132
4216
  if (isStandaloneStreamRequest(input, init, endpoint)) return new Response(null, {
@@ -4152,8 +4236,7 @@ function isStandaloneStreamRequest(input, init, endpoint) {
4152
4236
  const headers = new Headers(init?.headers ?? request?.headers);
4153
4237
  return (headers.get("accept")?.toLowerCase() ?? "").includes("text/event-stream") && !headers.has("last-event-id");
4154
4238
  }
4155
- //#endregion
4156
- //#region ../../core/mcp/node/transport.ts
4239
+ // ../../core/mcp/node/transport.ts
4157
4240
  function headersFromSettings(settings) {
4158
4241
  if (!settings || settings.headers.length === 0) return void 0;
4159
4242
  const out = {};
@@ -4235,8 +4318,7 @@ function createTransportNode(config, options = {}) {
4235
4318
  }) };
4236
4319
  }
4237
4320
  }
4238
- //#endregion
4239
- //#region ../../core/client/config-parse.ts
4321
+ // ../../core/client/config-parse.ts
4240
4322
  function isAbsoluteHttpUrl(value) {
4241
4323
  let url;
4242
4324
  try {
@@ -4319,8 +4401,7 @@ const ClientConfigSchema = z$1.object({
4319
4401
  function parseClientConfig(raw) {
4320
4402
  return ClientConfigSchema.parse(raw);
4321
4403
  }
4322
- //#endregion
4323
- //#region ../../core/client/secrets.ts
4404
+ // ../../core/client/secrets.ts
4324
4405
  const CLIENT_KEYCHAIN_ID = "client";
4325
4406
  function hasClientPlaintextSecret(config) {
4326
4407
  const secret = config.enterpriseManagedAuth?.idp?.clientSecret;
@@ -4361,8 +4442,7 @@ function mergeSecretsIntoClientConfig(config, secrets) {
4361
4442
  }
4362
4443
  };
4363
4444
  }
4364
- //#endregion
4365
- //#region ../../core/client/node-persistence.ts
4445
+ // ../../core/client/node-persistence.ts
4366
4446
  async function withClientConfigLock(filePath, action, body) {
4367
4447
  let entered = false;
4368
4448
  try {
@@ -4412,8 +4492,7 @@ async function readClientConfigStore(filePath, secretStore) {
4412
4492
  const secrets = await readIdpSecretFromKeychain(secretStore);
4413
4493
  return mergeSecretsIntoClientConfig(config, secrets);
4414
4494
  }
4415
- //#endregion
4416
- //#region ../../core/client/config.ts
4495
+ // ../../core/client/config.ts
4417
4496
  function getClientConfigFilePath(customPath) {
4418
4497
  return customPath ?? getStoreFilePath(getDefaultStorageDir(), "client");
4419
4498
  }
@@ -4424,8 +4503,7 @@ async function loadClientConfig(options) {
4424
4503
  if (raw === null) return {};
4425
4504
  return parseClientConfig(parseStore(raw));
4426
4505
  }
4427
- //#endregion
4428
- //#region ../../core/client/types.ts
4506
+ // ../../core/client/types.ts
4429
4507
  function isEnterpriseManagedAuthEnabled(config) {
4430
4508
  const ema = config.enterpriseManagedAuth;
4431
4509
  if (!ema?.idp) return false;
@@ -4442,8 +4520,7 @@ function getActiveCimdClientMetadataUrl(config) {
4442
4520
  if (!isCimdEnabled(config)) return void 0;
4443
4521
  return config.cimd?.clientMetadataUrl?.trim() || void 0;
4444
4522
  }
4445
- //#endregion
4446
- //#region ../../core/client/runner.ts
4523
+ // ../../core/client/runner.ts
4447
4524
  async function loadRunnerClientConfig(options) {
4448
4525
  return loadClientConfig({
4449
4526
  filePath: options?.clientConfigPath?.trim() || process.env.MCP_CLIENT_CONFIG_PATH?.trim() || void 0,
@@ -4486,8 +4563,7 @@ function buildRunnerClientAuthOptions(clientConfig, savedSettings, cliOverrides)
4486
4563
  ...oauth && { directAuthRecovery: true }
4487
4564
  };
4488
4565
  }
4489
- //#endregion
4490
- //#region ../../core/node/version.ts
4566
+ // ../../core/node/version.ts
4491
4567
  const ROOT_PACKAGE_NAME = "@modelcontextprotocol/inspector";
4492
4568
  function readInspectorVersion(callerUrl) {
4493
4569
  const startDir = dirname$1(fileURLToPath$1(callerUrl));
@@ -4504,8 +4580,7 @@ function readInspectorVersion(callerUrl) {
4504
4580
  }
4505
4581
  throw new Error(`Could not locate the ${ROOT_PACKAGE_NAME} root package.json above ${startDir}`);
4506
4582
  }
4507
- //#endregion
4508
- //#region ../../core/node/hostUrl.ts
4583
+ // ../../core/node/hostUrl.ts
4509
4584
  function stripBrackets(host) {
4510
4585
  return host.replace(/^\[(.*)\]$/, "$1");
4511
4586
  }
@@ -4533,8 +4608,7 @@ function isLoopbackHost(host) {
4533
4608
  const h = canonicalUrlHost(host).replace(/\.$/, "");
4534
4609
  return h === "localhost" || h === "[::1]" || /^127(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/.test(h);
4535
4610
  }
4536
- //#endregion
4537
- //#region ../../core/auth/node/runner-oauth-callback.ts
4611
+ // ../../core/auth/node/runner-oauth-callback.ts
4538
4612
  const RUNNER_OAUTH_CALLBACK_DEFAULT_HOSTNAME = "127.0.0.1";
4539
4613
  const RUNNER_OAUTH_CALLBACK_DEFAULT_PORT = 6276;
4540
4614
  const RUNNER_OAUTH_CALLBACK_PATH = "/oauth/callback";
@@ -4578,8 +4652,7 @@ function parseRunnerOAuthCallbackUrl(cliCallbackUrl) {
4578
4652
  function formatRunnerOAuthRedirectUrl(config) {
4579
4653
  return `http://${formatHostForUrl(config.hostname)}:${config.port}${config.pathname}`;
4580
4654
  }
4581
- //#endregion
4582
- //#region ../../core/json/xMcpHeader.ts
4655
+ // ../../core/json/xMcpHeader.ts
4583
4656
  const X_MCP_HEADER_KEY = "x-mcp-header";
4584
4657
  const MCP_PARAM_HEADER_PREFIX = "Mcp-Param-";
4585
4658
  const RFC9110_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
@@ -4727,8 +4800,7 @@ function mcpParamHeadersForTool(tool, args) {
4727
4800
  if (!scan.valid || scan.declarations.length === 0) return {};
4728
4801
  return buildMcpParamHeaders(scan.declarations, args);
4729
4802
  }
4730
- //#endregion
4731
- //#region ../../core/mcp/subscriptionAck.ts
4803
+ // ../../core/mcp/subscriptionAck.ts
4732
4804
  const NEVER_ACKNOWLEDGED_SDK_MESSAGE = "closed the subscription gracefully before acknowledging";
4733
4805
  const NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE = "The server closed the subscription without acknowledging it. A subscriptions/listen request must first be answered with a notifications/subscriptions/acknowledged notification; a JSON-RPC result for the listen id means graceful closure. Not retrying — the server would answer the same way again.";
4734
4806
  function isNeverAcknowledgedSubscriptionClose(error) {
@@ -4738,8 +4810,7 @@ function subscriptionFailureMessage(error) {
4738
4810
  if (isNeverAcknowledgedSubscriptionClose(error)) return NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE;
4739
4811
  return error instanceof Error ? error.message : String(error);
4740
4812
  }
4741
- //#endregion
4742
- //#region ../../core/mcp/subscriptionRefusal.ts
4813
+ // ../../core/mcp/subscriptionRefusal.ts
4743
4814
  const REFUSAL_STATUSES = /* @__PURE__ */ new Set([
4744
4815
  400,
4745
4816
  403,
@@ -4756,8 +4827,7 @@ function subscriptionListenRefusal(error) {
4756
4827
  function subscriptionListenRefusalMessage(refusal) {
4757
4828
  return `The server refused subscriptions/listen (HTTP ${refusal.statusText ? `${refusal.status} ${refusal.statusText}` : String(refusal.status)}). Not retrying — the server would answer the same way again.`;
4758
4829
  }
4759
- //#endregion
4760
- //#region ../../core/mcp/messageTrackingTransport.ts
4830
+ // ../../core/mcp/messageTrackingTransport.ts
4761
4831
  var MessageTrackingTransport = class {
4762
4832
  baseTransport;
4763
4833
  callbacks;
@@ -4830,8 +4900,7 @@ var MessageTrackingTransport = class {
4830
4900
  return this.negotiatedProtocolVersion;
4831
4901
  }
4832
4902
  };
4833
- //#endregion
4834
- //#region ../../core/extension/tasks/errors.ts
4903
+ // ../../core/extension/tasks/errors.ts
4835
4904
  function abortError(signal) {
4836
4905
  return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
4837
4906
  }
@@ -4845,14 +4914,12 @@ function toProtocolError(reason) {
4845
4914
  const normalized = unwrapTaskDispatchError(reason);
4846
4915
  return normalized instanceof ProtocolError ? normalized : new ProtocolError(ProtocolErrorCode.InternalError, normalized instanceof Error ? normalized.message : String(normalized));
4847
4916
  }
4848
- //#endregion
4849
- //#region ../../core/extension/tasks/notificationSchemas.ts
4917
+ // ../../core/extension/tasks/notificationSchemas.ts
4850
4918
  const TasksListChangedNotificationSchema = NotificationSchema.extend({
4851
4919
  method: z.literal("notifications/tasks/list_changed"),
4852
4920
  params: z.record(z.string(), z.unknown()).optional()
4853
4921
  });
4854
- //#endregion
4855
- //#region ../../core/extension/tasks/progress.ts
4922
+ // ../../core/extension/tasks/progress.ts
4856
4923
  var TaskProgressRouter = class {
4857
4924
  taskIds = /* @__PURE__ */ new Map();
4858
4925
  owners = /* @__PURE__ */ new Map();
@@ -4883,8 +4950,7 @@ var TaskProgressRouter = class {
4883
4950
  this.owners.clear();
4884
4951
  }
4885
4952
  };
4886
- //#endregion
4887
- //#region ../../core/extension/tasks/rawWireChannel.ts
4953
+ // ../../core/extension/tasks/rawWireChannel.ts
4888
4954
  const RAW_WIRE_ID_PREFIX = "inspector-ext-";
4889
4955
  var RawWireChannel = class {
4890
4956
  pending = /* @__PURE__ */ new Map();
@@ -5013,8 +5079,7 @@ var RawWireChannel = class {
5013
5079
  }
5014
5080
  }
5015
5081
  };
5016
- //#endregion
5017
- //#region ../../core/extension/tasks/session.ts
5082
+ // ../../core/extension/tasks/session.ts
5018
5083
  function taskSessionEndpointId(config, clientInfo) {
5019
5084
  return createTaskSessionEndpointId("inspector", config.type === "sse" || config.type === "streamable-http" ? {
5020
5085
  host: clientInfo,
@@ -5037,8 +5102,7 @@ function isTasksExtensionNegotiated(era, capabilities) {
5037
5102
  const extension = capabilities?.extensions?.[TASKS_EXTENSION_KEY];
5038
5103
  return extension !== null && typeof extension === "object" && !Array.isArray(extension) && Object.keys(extension).length === 0;
5039
5104
  }
5040
- //#endregion
5041
- //#region ../../core/extension/tasks/wire.ts
5105
+ // ../../core/extension/tasks/wire.ts
5042
5106
  const taskToolResultCodec = runtimeCodecFromStandardSchema({ "~standard": {
5043
5107
  version: 1,
5044
5108
  vendor: "mcp-inspector",
@@ -5075,8 +5139,7 @@ function taskInputOrigin(delivery) {
5075
5139
  if (delivery === "request-retry") return "input-required";
5076
5140
  return "server-request";
5077
5141
  }
5078
- //#endregion
5079
- //#region ../../core/mcp/extensions.ts
5142
+ // ../../core/mcp/extensions.ts
5080
5143
  const EMA_EXTENSION_KEY = "io.modelcontextprotocol/enterprise-managed-authorization";
5081
5144
  const UI_EXTENSION_KEY = "io.modelcontextprotocol/ui";
5082
5145
  const MCP_APP_MIME_TYPE = RESOURCE_MIME_TYPE;
@@ -5113,8 +5176,7 @@ function buildClientExtensions(input) {
5113
5176
  if (input.enterpriseManaged) map[EMA_EXTENSION_KEY] = {};
5114
5177
  return map;
5115
5178
  }
5116
- //#endregion
5117
- //#region ../../core/mcp/appElicitation.ts
5179
+ // ../../core/mcp/appElicitation.ts
5118
5180
  function uiExtension(capabilities) {
5119
5181
  const ext = capabilities?.extensions?.[UI_EXTENSION_KEY];
5120
5182
  return typeof ext === "object" && ext !== null ? ext : void 0;
@@ -5169,8 +5231,7 @@ function validateAppElicitResult(provider, params, result) {
5169
5231
  return;
5170
5232
  }
5171
5233
  }
5172
- //#endregion
5173
- //#region ../../core/mcp/toolOutputValidation.ts
5234
+ // ../../core/mcp/toolOutputValidation.ts
5174
5235
  function validateToolOutput(provider, tool, result) {
5175
5236
  if (!tool.outputSchema) return void 0;
5176
5237
  const structured = result.structuredContent;
@@ -5182,6 +5243,625 @@ function validateToolOutput(provider, tool, result) {
5182
5243
  return;
5183
5244
  }
5184
5245
  }
5246
+ // ../../core/json/linearRegExp.ts
5247
+ var CharMatcher = class {
5248
+ re;
5249
+ ascii = /* @__PURE__ */ new Uint8Array(128);
5250
+ constructor(source, unicode) {
5251
+ this.re = new RegExp(`^(?:${source})$`, unicode ? "u" : "");
5252
+ }
5253
+ matches(cp, unicode) {
5254
+ if (cp < 128) {
5255
+ const memo = this.ascii[cp];
5256
+ if (memo !== 0) return memo === 1;
5257
+ const result = this.re.test(String.fromCharCode(cp));
5258
+ this.ascii[cp] = result ? 1 : 2;
5259
+ return result;
5260
+ }
5261
+ return this.re.test(unicode ? String.fromCodePoint(cp) : String.fromCharCode(cp));
5262
+ }
5263
+ };
5264
+ var Unsupported = class extends Error {};
5265
+ const MAX_GROUP_DEPTH = 64;
5266
+ const MAX_PROGRAM_SIZE = 1e4;
5267
+ const MAX_COMPILE_STEPS = 10 * MAX_PROGRAM_SIZE;
5268
+ const MAX_PATTERN_LENGTH = 8192;
5269
+ const COMPILE_BUDGET_EXHAUSTED = "the patterns together exceed the compilation budget";
5270
+ function isCompileBudgetExhausted(budget) {
5271
+ return budget.steps < 0 || budget.size < 0;
5272
+ }
5273
+ const QUANTIFIER_BRACES = /\{(\d+)(?:(,)(\d*))?\}/y;
5274
+ const HEX4 = /^[0-9a-fA-F]{4}$/;
5275
+ const HEX2 = /^[0-9a-fA-F]{2}$/;
5276
+ var Parser = class {
5277
+ pos = 0;
5278
+ src;
5279
+ unicode;
5280
+ constructor(src, unicode) {
5281
+ this.src = src;
5282
+ this.unicode = unicode;
5283
+ }
5284
+ parse() {
5285
+ const node = this.parseAlternation(0);
5286
+ /* v8 ignore next -- the native RegExp constructor rejects an unbalanced `)` first */
5287
+ if (this.pos !== this.src.length) throw new Unsupported("unbalanced group");
5288
+ return node;
5289
+ }
5290
+ parseAlternation(depth) {
5291
+ const options = [this.parseSequence(depth)];
5292
+ while (this.src[this.pos] === "|") {
5293
+ this.pos++;
5294
+ options.push(this.parseSequence(depth));
5295
+ }
5296
+ return options.length === 1 ? options[0] : {
5297
+ kind: "alt",
5298
+ options
5299
+ };
5300
+ }
5301
+ parseSequence(depth) {
5302
+ const items = [];
5303
+ while (this.pos < this.src.length && this.src[this.pos] !== "|" && this.src[this.pos] !== ")") items.push(this.parseTerm(depth));
5304
+ return items.length === 1 ? items[0] : {
5305
+ kind: "seq",
5306
+ items
5307
+ };
5308
+ }
5309
+ parseTerm(depth) {
5310
+ const atom = this.parseAtom(depth);
5311
+ const quantifier = this.readQuantifier();
5312
+ if (!quantifier) return atom;
5313
+ if (this.src[this.pos] === "?") this.pos++;
5314
+ return {
5315
+ kind: "repeat",
5316
+ body: atom,
5317
+ ...quantifier
5318
+ };
5319
+ }
5320
+ readQuantifier() {
5321
+ const c = this.src[this.pos];
5322
+ if (c === "*") {
5323
+ this.pos++;
5324
+ return {
5325
+ min: 0,
5326
+ max: Infinity
5327
+ };
5328
+ }
5329
+ if (c === "+") {
5330
+ this.pos++;
5331
+ return {
5332
+ min: 1,
5333
+ max: Infinity
5334
+ };
5335
+ }
5336
+ if (c === "?") {
5337
+ this.pos++;
5338
+ return {
5339
+ min: 0,
5340
+ max: 1
5341
+ };
5342
+ }
5343
+ if (c === "{") {
5344
+ QUANTIFIER_BRACES.lastIndex = this.pos;
5345
+ const m = QUANTIFIER_BRACES.exec(this.src);
5346
+ if (!m) return void 0;
5347
+ this.pos += m[0].length;
5348
+ const min = Number(m[1]);
5349
+ return {
5350
+ min,
5351
+ max: m[2] === void 0 ? min : m[3] ? Number(m[3]) : Infinity
5352
+ };
5353
+ }
5354
+ }
5355
+ parseAtom(depth) {
5356
+ switch (this.src[this.pos]) {
5357
+ case "(": return this.parseGroup(depth);
5358
+ case "[": return this.parseClass();
5359
+ case "\\": return this.parseEscape();
5360
+ case ".":
5361
+ this.pos++;
5362
+ return {
5363
+ kind: "char",
5364
+ source: "."
5365
+ };
5366
+ case "^":
5367
+ this.pos++;
5368
+ return {
5369
+ kind: "assert",
5370
+ assertion: "start"
5371
+ };
5372
+ case "$":
5373
+ this.pos++;
5374
+ return {
5375
+ kind: "assert",
5376
+ assertion: "end"
5377
+ };
5378
+ case "*":
5379
+ case "+":
5380
+ case "?":
5381
+ /* v8 ignore next -- "nothing to repeat" is a native syntax error */
5382
+ throw new Unsupported("nothing to repeat");
5383
+ case "{":
5384
+ QUANTIFIER_BRACES.lastIndex = this.pos;
5385
+ if (QUANTIFIER_BRACES.test(this.src))
5386
+ /* v8 ignore next -- rejected by the native RegExp constructor first */
5387
+ throw new Unsupported("nothing to repeat");
5388
+ this.pos++;
5389
+ return {
5390
+ kind: "char",
5391
+ source: "\\{"
5392
+ };
5393
+ default: {
5394
+ const width = this.codePointWidth(this.pos);
5395
+ const source = this.src.slice(this.pos, this.pos + width);
5396
+ this.pos += width;
5397
+ return {
5398
+ kind: "char",
5399
+ source
5400
+ };
5401
+ }
5402
+ }
5403
+ }
5404
+ codePointWidth(at) {
5405
+ if (!this.unicode) return 1;
5406
+ return this.src.codePointAt(at) > 65535 ? 2 : 1;
5407
+ }
5408
+ parseGroup(depth) {
5409
+ if (depth >= MAX_GROUP_DEPTH) throw new Unsupported("groups nested too deeply");
5410
+ this.pos++;
5411
+ if (this.src.startsWith("?:", this.pos)) this.pos += 2;
5412
+ else if (this.src.startsWith("?<", this.pos) && this.src[this.pos + 2] !== "=" && this.src[this.pos + 2] !== "!") {
5413
+ const close = this.src.indexOf(">", this.pos);
5414
+ /* v8 ignore next -- an unterminated group name is a native syntax error */
5415
+ if (close < 0) throw new Unsupported("unterminated group name");
5416
+ this.pos = close + 1;
5417
+ } else if (this.src[this.pos] === "?") throw new Unsupported("lookaround or group modifier");
5418
+ const body = this.parseAlternation(depth + 1);
5419
+ /* v8 ignore next -- an unterminated group is a native syntax error */
5420
+ if (this.src[this.pos] !== ")") throw new Unsupported("unterminated group");
5421
+ this.pos++;
5422
+ return body;
5423
+ }
5424
+ parseClass() {
5425
+ const start = this.pos;
5426
+ this.pos++;
5427
+ while (this.pos < this.src.length && this.src[this.pos] !== "]") this.pos += this.src[this.pos] === "\\" ? 2 : 1;
5428
+ /* v8 ignore next -- an unterminated class is a native syntax error */
5429
+ if (this.pos >= this.src.length) throw new Unsupported("unterminated class");
5430
+ this.pos++;
5431
+ return {
5432
+ kind: "char",
5433
+ source: this.src.slice(start, this.pos)
5434
+ };
5435
+ }
5436
+ parseEscape() {
5437
+ const next = this.src[this.pos + 1];
5438
+ /* v8 ignore next -- a trailing backslash is a native syntax error */
5439
+ if (next === void 0) throw new Unsupported("trailing backslash");
5440
+ switch (next) {
5441
+ case "b":
5442
+ this.pos += 2;
5443
+ return {
5444
+ kind: "assert",
5445
+ assertion: "wordBoundary"
5446
+ };
5447
+ case "B":
5448
+ this.pos += 2;
5449
+ return {
5450
+ kind: "assert",
5451
+ assertion: "notWordBoundary"
5452
+ };
5453
+ case "1":
5454
+ case "2":
5455
+ case "3":
5456
+ case "4":
5457
+ case "5":
5458
+ case "6":
5459
+ case "7":
5460
+ case "8":
5461
+ case "9":
5462
+ case "k": throw new Unsupported("backreference");
5463
+ case "0":
5464
+ if (/[0-9]/.test(this.src[this.pos + 2] ?? "")) throw new Unsupported("octal escape");
5465
+ return this.takeChar(2);
5466
+ case "c":
5467
+ if (!/[a-zA-Z]/.test(this.src[this.pos + 2] ?? "")) throw new Unsupported("incomplete control escape");
5468
+ return this.takeChar(3);
5469
+ case "p":
5470
+ case "P":
5471
+ if (this.unicode && this.src[this.pos + 2] === "{") return this.takeThrough("}");
5472
+ return this.takeChar(2);
5473
+ case "x": return this.takeChar(HEX2.test(this.src.slice(this.pos + 2, this.pos + 4)) ? 4 : 2);
5474
+ case "u": return this.parseUnicodeEscape();
5475
+ default: return this.takeChar(1 + this.codePointWidth(this.pos + 1));
5476
+ }
5477
+ }
5478
+ parseUnicodeEscape() {
5479
+ if (this.unicode && this.src[this.pos + 2] === "{") return this.takeThrough("}");
5480
+ const hex = this.src.slice(this.pos + 2, this.pos + 6);
5481
+ if (!HEX4.test(hex)) return this.takeChar(2);
5482
+ const unit = parseInt(hex, 16);
5483
+ if (this.unicode && unit >= 55296 && unit <= 56319 && this.src.startsWith("\\u", this.pos + 6)) {
5484
+ const low = this.src.slice(this.pos + 8, this.pos + 12);
5485
+ if (HEX4.test(low)) {
5486
+ const lowUnit = parseInt(low, 16);
5487
+ if (lowUnit >= 56320 && lowUnit <= 57343) return this.takeChar(12);
5488
+ }
5489
+ }
5490
+ return this.takeChar(6);
5491
+ }
5492
+ takeChar(length) {
5493
+ const source = this.src.slice(this.pos, this.pos + length);
5494
+ this.pos += length;
5495
+ return {
5496
+ kind: "char",
5497
+ source
5498
+ };
5499
+ }
5500
+ takeThrough(terminator) {
5501
+ const end = this.src.indexOf(terminator, this.pos);
5502
+ /* v8 ignore next -- an unterminated `\p{` / `\u{` is a native syntax error */
5503
+ if (end < 0) throw new Unsupported("unterminated escape");
5504
+ return this.takeChar(end + 1 - this.pos);
5505
+ }
5506
+ };
5507
+ var Compiler = class {
5508
+ prog = [];
5509
+ matchers = /* @__PURE__ */ new Map();
5510
+ unicode;
5511
+ budget;
5512
+ steps = 0;
5513
+ constructor(unicode, budget) {
5514
+ this.unicode = unicode;
5515
+ this.budget = budget;
5516
+ }
5517
+ emit(inst) {
5518
+ if (this.prog.length >= 1e4) throw new Unsupported("pattern too complex");
5519
+ if (this.budget && --this.budget.size < 0) throw new Unsupported(COMPILE_BUDGET_EXHAUSTED);
5520
+ this.prog.push(inst);
5521
+ return this.prog.length - 1;
5522
+ }
5523
+ matcher(source) {
5524
+ let matcher = this.matchers.get(source);
5525
+ if (!matcher) {
5526
+ try {
5527
+ matcher = new CharMatcher(source, this.unicode);
5528
+ } catch {
5529
+ /* v8 ignore start -- defensive: each atom is a slice the native constructor already accepted in context */
5530
+ throw new Unsupported("unrecognized character syntax");
5531
+ }
5532
+ this.matchers.set(source, matcher);
5533
+ }
5534
+ return matcher;
5535
+ }
5536
+ compile(node) {
5537
+ if (++this.steps > 1e5) throw new Unsupported("pattern too complex");
5538
+ if (this.budget && --this.budget.steps < 0) throw new Unsupported(COMPILE_BUDGET_EXHAUSTED);
5539
+ switch (node.kind) {
5540
+ case "char":
5541
+ this.emit({
5542
+ op: "char",
5543
+ matcher: this.matcher(node.source)
5544
+ });
5545
+ return;
5546
+ case "assert":
5547
+ this.emit({
5548
+ op: "assert",
5549
+ assertion: node.assertion
5550
+ });
5551
+ return;
5552
+ case "seq":
5553
+ for (const item of node.items) this.compile(item);
5554
+ return;
5555
+ case "alt":
5556
+ this.compileAlternation(node.options);
5557
+ return;
5558
+ case "repeat":
5559
+ this.compileRepeat(node.body, node.min, node.max);
5560
+ return;
5561
+ }
5562
+ }
5563
+ compileAlternation(options) {
5564
+ const jumps = [];
5565
+ for (let i = 0; i < options.length - 1; i++) {
5566
+ const split = this.emit({
5567
+ op: "split",
5568
+ a: 0,
5569
+ b: 0
5570
+ });
5571
+ this.patchSplit(split, split + 1, -1);
5572
+ this.compile(options[i]);
5573
+ jumps.push(this.emit({
5574
+ op: "jmp",
5575
+ to: 0
5576
+ }));
5577
+ this.patchSplit(split, -1, this.prog.length);
5578
+ }
5579
+ this.compile(options[options.length - 1]);
5580
+ for (const jump of jumps) this.patchJump(jump, this.prog.length);
5581
+ }
5582
+ compileRepeat(body, min, max) {
5583
+ for (let i = 0; i < min; i++) {
5584
+ const before = this.prog.length;
5585
+ this.compile(body);
5586
+ if (this.prog.length === before) return;
5587
+ }
5588
+ if (max === Infinity) {
5589
+ const split = this.emit({
5590
+ op: "split",
5591
+ a: 0,
5592
+ b: 0
5593
+ });
5594
+ this.compile(body);
5595
+ this.emit({
5596
+ op: "jmp",
5597
+ to: split
5598
+ });
5599
+ this.patchSplit(split, split + 1, this.prog.length);
5600
+ return;
5601
+ }
5602
+ const splits = [];
5603
+ for (let i = min; i < max; i++) {
5604
+ const split = this.emit({
5605
+ op: "split",
5606
+ a: 0,
5607
+ b: 0
5608
+ });
5609
+ this.patchSplit(split, split + 1, -1);
5610
+ splits.push(split);
5611
+ this.compile(body);
5612
+ }
5613
+ for (const split of splits) this.patchSplit(split, -1, this.prog.length);
5614
+ }
5615
+ patchSplit(at, a, b) {
5616
+ const inst = this.prog[at];
5617
+ if (a >= 0) inst.a = a;
5618
+ if (b >= 0) inst.b = b;
5619
+ }
5620
+ patchJump(at, to) {
5621
+ this.prog[at].to = to;
5622
+ }
5623
+ };
5624
+ function isWordUnit(unit) {
5625
+ return unit >= 48 && unit <= 57 || unit >= 65 && unit <= 90 || unit >= 97 && unit <= 122 || unit === 95;
5626
+ }
5627
+ var LinearRegExp = class {
5628
+ anchoredStart;
5629
+ prog;
5630
+ unicode;
5631
+ constructor(prog, unicode) {
5632
+ this.prog = prog;
5633
+ this.unicode = unicode;
5634
+ const first = prog[0];
5635
+ this.anchoredStart = first !== void 0 && first.op === "assert" && first.assertion === "start";
5636
+ }
5637
+ get size() {
5638
+ return this.prog.length;
5639
+ }
5640
+ cost(input) {
5641
+ return (input.length + 1) * this.prog.length;
5642
+ }
5643
+ search(input, budget) {
5644
+ if (this.cost(input) > budget) return void 0;
5645
+ const prog = this.prog;
5646
+ const size = prog.length;
5647
+ const mark = new Int32Array(size).fill(-1);
5648
+ const stack = [];
5649
+ let clist = new Int32Array(size);
5650
+ let nlist = new Int32Array(size);
5651
+ const add = (list, count, start, pos, generation) => {
5652
+ stack.push(start);
5653
+ while (stack.length > 0) {
5654
+ const pc = stack.pop();
5655
+ if (mark[pc] === generation) continue;
5656
+ mark[pc] = generation;
5657
+ const inst = prog[pc];
5658
+ switch (inst.op) {
5659
+ case "match":
5660
+ stack.length = 0;
5661
+ return -1;
5662
+ case "jmp":
5663
+ stack.push(inst.to);
5664
+ break;
5665
+ case "split":
5666
+ stack.push(inst.b, inst.a);
5667
+ break;
5668
+ case "assert":
5669
+ if (this.holds(inst.assertion, input, pos)) stack.push(pc + 1);
5670
+ break;
5671
+ case "char": list[count++] = pc;
5672
+ }
5673
+ }
5674
+ return count;
5675
+ };
5676
+ let pos = 0;
5677
+ let generation = 0;
5678
+ let clen = add(clist, 0, 0, pos, generation);
5679
+ if (clen < 0) return true;
5680
+ while (pos < input.length) {
5681
+ if (this.anchoredStart && clen === 0) return false;
5682
+ const cp = this.unicode ? input.codePointAt(pos) : input.charCodeAt(pos);
5683
+ const next = pos + (this.unicode && cp > 65535 ? 2 : 1);
5684
+ generation++;
5685
+ let nlen = 0;
5686
+ for (let i = 0; i < clen; i++) {
5687
+ const pc = clist[i];
5688
+ if (prog[pc].matcher.matches(cp, this.unicode)) {
5689
+ nlen = add(nlist, nlen, pc + 1, next, generation);
5690
+ if (nlen < 0) return true;
5691
+ }
5692
+ }
5693
+ nlen = add(nlist, nlen, 0, next, generation);
5694
+ if (nlen < 0) return true;
5695
+ [clist, nlist] = [nlist, clist];
5696
+ clen = nlen;
5697
+ pos = next;
5698
+ }
5699
+ return false;
5700
+ }
5701
+ holds(assertion, input, pos) {
5702
+ switch (assertion) {
5703
+ case "start": return pos === 0;
5704
+ case "end": return pos === input.length;
5705
+ case "wordBoundary":
5706
+ case "notWordBoundary": return (pos > 0 && isWordUnit(input.charCodeAt(pos - 1))) !== (pos < input.length && isWordUnit(input.charCodeAt(pos))) === (assertion === "wordBoundary");
5707
+ }
5708
+ }
5709
+ };
5710
+ function compileLinearRegExp(pattern, unicode, budget) {
5711
+ if (pattern.length > 8192) return {
5712
+ ok: false,
5713
+ reason: `pattern longer than ${MAX_PATTERN_LENGTH} characters`
5714
+ };
5715
+ if (budget) {
5716
+ budget.steps -= pattern.length;
5717
+ if (isCompileBudgetExhausted(budget)) return {
5718
+ ok: false,
5719
+ reason: COMPILE_BUDGET_EXHAUSTED
5720
+ };
5721
+ }
5722
+ new RegExp(pattern, unicode ? "u" : "");
5723
+ try {
5724
+ const ast = new Parser(pattern, unicode).parse();
5725
+ const compiler = new Compiler(unicode, budget);
5726
+ compiler.compile(ast);
5727
+ compiler.prog.push({ op: "match" });
5728
+ return {
5729
+ ok: true,
5730
+ regExp: new LinearRegExp(compiler.prog, unicode)
5731
+ };
5732
+ } catch (error) {
5733
+ /* v8 ignore next -- every throw inside the parser/compiler is an Unsupported */
5734
+ if (!(error instanceof Unsupported)) throw error;
5735
+ return {
5736
+ ok: false,
5737
+ reason: error.message
5738
+ };
5739
+ }
5740
+ }
5741
+ // ../../core/mcp/linearPatternValidator.ts
5742
+ const PATTERN_EVALUATION_BUDGET = 2e7;
5743
+ const SCHEMA_COMPILE_BUDGET = {
5744
+ steps: 10 * MAX_COMPILE_STEPS,
5745
+ size: 10 * MAX_PROGRAM_SIZE
5746
+ };
5747
+ const MAX_QUOTED_PATTERN = 120;
5748
+ const DRAFT_2020_12 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2020-12/schema", "http://json-schema.org/draft/2020-12/schema"]);
5749
+ const DRAFT_2019_09 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2019-09/schema", "http://json-schema.org/draft/2019-09/schema"]);
5750
+ const DRAFT_07_OR_06 = /* @__PURE__ */ new Set([
5751
+ "https://json-schema.org/draft-07/schema",
5752
+ "http://json-schema.org/draft-07/schema",
5753
+ "https://json-schema.org/draft-06/schema",
5754
+ "http://json-schema.org/draft-06/schema"
5755
+ ]);
5756
+ function declaredDialect(schema) {
5757
+ const declared = schema.$schema;
5758
+ if (typeof declared !== "string") return "2020-12";
5759
+ const uri = declared.replace(/#$/, "");
5760
+ if (DRAFT_2020_12.has(uri)) return "2020-12";
5761
+ if (DRAFT_2019_09.has(uri)) return "2019-09";
5762
+ if (DRAFT_07_OR_06.has(uri)) return "draft-7";
5763
+ throw new Error(`JSON Schema declares an unsupported dialect ("$schema": "${declared.slice(0, 200)}"). Supported: JSON Schema 2020-12, 2019-09, draft-07, and draft-06.`);
5764
+ }
5765
+ function quote(pattern) {
5766
+ return pattern.length > MAX_QUOTED_PATTERN ? `${pattern.slice(0, MAX_QUOTED_PATTERN)}…` : pattern;
5767
+ }
5768
+ var PatternLedger = class {
5769
+ remaining = PATTERN_EVALUATION_BUDGET;
5770
+ unevaluated = /* @__PURE__ */ new Set();
5771
+ reset() {
5772
+ this.remaining = PATTERN_EVALUATION_BUDGET;
5773
+ this.unevaluated.clear();
5774
+ }
5775
+ };
5776
+ var LinearPattern = class {
5777
+ source;
5778
+ flags;
5779
+ compiled;
5780
+ ledger;
5781
+ constructor(source, flags, compiled, ledger) {
5782
+ this.source = source;
5783
+ this.flags = flags;
5784
+ this.compiled = compiled;
5785
+ this.ledger = ledger;
5786
+ }
5787
+ test(input) {
5788
+ if (!this.compiled.ok) return this.skip(this.compiled.reason);
5789
+ const { regExp } = this.compiled;
5790
+ const cost = regExp.cost(input);
5791
+ if (cost > this.ledger.remaining) return this.skip(`checking a ${input.length}-character value would exceed the evaluation budget`);
5792
+ this.ledger.remaining -= cost;
5793
+ return regExp.search(input, cost) === true;
5794
+ }
5795
+ skip(reason) {
5796
+ this.ledger.unevaluated.add(`pattern "${quote(this.source)}" was not evaluated (${reason})`);
5797
+ return true;
5798
+ }
5799
+ toString() {
5800
+ return `/${this.source}/${this.flags}`;
5801
+ }
5802
+ };
5803
+ function createRegExpEngine(ledger, budget) {
5804
+ const engine = (pattern, flags) => new LinearPattern(pattern, flags, compileLinearRegExp(pattern, flags.includes("u"), budget()), ledger);
5805
+ return Object.assign(engine, { code: "linearRegExp" });
5806
+ }
5807
+ var LinearPatternJsonSchemaValidator = class {
5808
+ ledger = new PatternLedger();
5809
+ engines = /* @__PURE__ */ new Map();
5810
+ compileBudget = { ...SCHEMA_COMPILE_BUDGET };
5811
+ overBudget = /* @__PURE__ */ new WeakSet();
5812
+ engineFor(dialect) {
5813
+ let engine = this.engines.get(dialect);
5814
+ if (!engine) {
5815
+ const options = {
5816
+ strict: false,
5817
+ validateFormats: true,
5818
+ validateSchema: false,
5819
+ allErrors: true,
5820
+ code: { regExp: createRegExpEngine(this.ledger, () => this.compileBudget) }
5821
+ };
5822
+ engine = dialect === "2020-12" ? new Ajv2020(options) : dialect === "2019-09" ? new Ajv2019(options) : new Ajv(options);
5823
+ addFormats(engine);
5824
+ this.engines.set(dialect, engine);
5825
+ }
5826
+ return engine;
5827
+ }
5828
+ getValidator(schema) {
5829
+ const engine = this.engineFor(declaredDialect(schema));
5830
+ const id = schema.$id;
5831
+ const validate = this.tracked(() => (typeof id === "string" ? engine.getSchema(id) : void 0) ?? engine.compile(schema));
5832
+ const overBudget = this.overBudget.has(validate);
5833
+ return (input) => {
5834
+ this.ledger.reset();
5835
+ const valid = validate(input);
5836
+ const unevaluated = [...this.ledger.unevaluated];
5837
+ if (overBudget) unevaluated.unshift("the schema's patterns exceed the compilation budget");
5838
+ if (valid && unevaluated.length === 0) return {
5839
+ valid: true,
5840
+ data: input,
5841
+ errorMessage: void 0
5842
+ };
5843
+ const messages = valid ? [] : [engine.errorsText(validate.errors)];
5844
+ if (unevaluated.length > 0) messages.push(`${unevaluated.join("; ")}, so the value could not be verified against the schema`);
5845
+ return {
5846
+ valid: false,
5847
+ data: void 0,
5848
+ errorMessage: messages.join("; ")
5849
+ };
5850
+ };
5851
+ }
5852
+ tracked(run) {
5853
+ const outer = this.compileBudget;
5854
+ const budget = { ...SCHEMA_COMPILE_BUDGET };
5855
+ this.compileBudget = budget;
5856
+ try {
5857
+ const validate = run();
5858
+ if (isCompileBudgetExhausted(budget)) this.overBudget.add(validate);
5859
+ return validate;
5860
+ } finally {
5861
+ this.compileBudget = outer;
5862
+ }
5863
+ }
5864
+ };
5185
5865
  function listPaginationExceeded(method) {
5186
5866
  return /* @__PURE__ */ new Error(`Salvage walk for ${method} exceeded 64 pages without the server's pagination converging`);
5187
5867
  }
@@ -5282,8 +5962,7 @@ function stripExecution(tool) {
5282
5962
  function eraToolItemSchema(wire, normalize) {
5283
5963
  return wire.transform((parsed) => normalize(parsed));
5284
5964
  }
5285
- //#endregion
5286
- //#region ../../core/mcp/uriTemplate.ts
5965
+ // ../../core/mcp/uriTemplate.ts
5287
5966
  const OPERATORS = [
5288
5967
  "+",
5289
5968
  "#",
@@ -5508,8 +6187,7 @@ function valueLengthError(values, names) {
5508
6187
  function declaredNames(parts) {
5509
6188
  return [...new Set(parts.flatMap((part) => part.kind === "expression" ? part.names : []))];
5510
6189
  }
5511
- //#endregion
5512
- //#region ../../core/mcp/typedEventTarget.ts
6190
+ // ../../core/mcp/typedEventTarget.ts
5513
6191
  var TypedEventGeneric = class extends CustomEvent {
5514
6192
  constructor(type, detail) {
5515
6193
  super(type, { detail });
@@ -5535,11 +6213,9 @@ var TypedEventTarget = class extends EventTarget {
5535
6213
  super.removeEventListener(type, listener, options);
5536
6214
  }
5537
6215
  };
5538
- //#endregion
5539
- //#region ../../core/mcp/inspectorClientEventTarget.ts
6216
+ // ../../core/mcp/inspectorClientEventTarget.ts
5540
6217
  var InspectorClientEventTarget = class extends TypedEventTarget {};
5541
- //#endregion
5542
- //#region ../../core/mcp/samplingCreateMessage.ts
6218
+ // ../../core/mcp/samplingCreateMessage.ts
5543
6219
  var SamplingCreateMessage = class {
5544
6220
  id;
5545
6221
  timestamp;
@@ -5583,8 +6259,7 @@ var SamplingCreateMessage = class {
5583
6259
  this.onRemove(this.id);
5584
6260
  }
5585
6261
  };
5586
- //#endregion
5587
- //#region ../../core/mcp/elicitationCreateMessage.ts
6262
+ // ../../core/mcp/elicitationCreateMessage.ts
5588
6263
  var ElicitationCreateMessage = class {
5589
6264
  id;
5590
6265
  timestamp;
@@ -5631,8 +6306,7 @@ var ElicitationCreateMessage = class {
5631
6306
  this.onRemove(this.id);
5632
6307
  }
5633
6308
  };
5634
- //#endregion
5635
- //#region ../../core/mcp/urlElicitation.ts
6309
+ // ../../core/mcp/urlElicitation.ts
5636
6310
  var UrlElicitationLoopError = class extends Error {
5637
6311
  url;
5638
6312
  constructor(url) {
@@ -5646,8 +6320,7 @@ function getUrlElicitationsFromError(error) {
5646
6320
  if (error instanceof ProtocolError && error.code === ProtocolErrorCode.UrlElicitationRequired) return error.data?.elicitations ?? [];
5647
6321
  return null;
5648
6322
  }
5649
- //#endregion
5650
- //#region ../../core/mcp/toolCallCancelledError.ts
6323
+ // ../../core/mcp/toolCallCancelledError.ts
5651
6324
  var ToolCallCancelledError = class extends Error {
5652
6325
  toolName;
5653
6326
  constructor(toolName) {
@@ -5656,8 +6329,7 @@ var ToolCallCancelledError = class extends Error {
5656
6329
  this.toolName = toolName;
5657
6330
  }
5658
6331
  };
5659
- //#endregion
5660
- //#region ../../core/auth/endpointOverrides.ts
6332
+ // ../../core/auth/endpointOverrides.ts
5661
6333
  const OVERRIDE_FIELDS = {
5662
6334
  authorizationUrl: "authorization_endpoint",
5663
6335
  tokenUrl: "token_endpoint"
@@ -5834,8 +6506,7 @@ function withOAuthEndpointOverrides(fetchFn, getOverrides) {
5834
6506
  return responseWithBody(response, JSON.stringify(applyOAuthEndpointOverrides(parsed, overrides)));
5835
6507
  };
5836
6508
  }
5837
- //#endregion
5838
- //#region ../../core/auth/oidcDiscoveryCompat.ts
6509
+ // ../../core/auth/oidcDiscoveryCompat.ts
5839
6510
  const RFC8414_WELL_KNOWN = "/.well-known/oauth-authorization-server";
5840
6511
  const OIDC_WELL_KNOWN$1 = "/.well-known/openid-configuration";
5841
6512
  const COMPAT_SOURCE_HEADER = "x-inspector-oauth-metadata-source";
@@ -5957,8 +6628,7 @@ function withRfc8414OidcCompat(fetchFn) {
5957
6628
  return response;
5958
6629
  };
5959
6630
  }
5960
- //#endregion
5961
- //#region ../../core/logging/logger.ts
6631
+ // ../../core/logging/logger.ts
5962
6632
  const noop = () => {};
5963
6633
  function createSilentLogger() {
5964
6634
  const logger = {
@@ -5975,8 +6645,7 @@ function createSilentLogger() {
5975
6645
  return logger;
5976
6646
  }
5977
6647
  const silentLogger = createSilentLogger();
5978
- //#endregion
5979
- //#region ../../core/mcp/connectionDiagnostics.ts
6648
+ // ../../core/mcp/connectionDiagnostics.ts
5980
6649
  function isRequestTimeoutData(value) {
5981
6650
  return typeof value === "object" && value !== null && typeof value.timeout === "number";
5982
6651
  }
@@ -5998,7 +6667,7 @@ function httpStatusTextOf(err) {
5998
6667
  if (typeof err !== "object" || err === null || !("statusText" in err)) return;
5999
6668
  return typeof err.statusText === "string" ? err.statusText : void 0;
6000
6669
  }
6001
- function formatDuration(ms) {
6670
+ function formatDuration$1(ms) {
6002
6671
  const clamped = Math.max(0, ms);
6003
6672
  if (clamped < 1e3) return `${Math.round(clamped)}ms`;
6004
6673
  const totalSeconds = Math.round(clamped / 1e3);
@@ -6021,7 +6690,7 @@ function plural(count, noun) {
6021
6690
  }
6022
6691
  function describeOutstanding(requests, now) {
6023
6692
  if (requests.length === 0) return "No requests are unanswered.";
6024
- const listed = requests.slice(0, 5).map((r) => `${r.method} (sent ${formatDuration(now - r.sentAt)} ago)`);
6693
+ const listed = requests.slice(0, 5).map((r) => `${r.method} (sent ${formatDuration$1(now - r.sentAt)} ago)`);
6025
6694
  const rest = requests.length - listed.length;
6026
6695
  const tail = rest > 0 ? `, and ${rest} more` : "";
6027
6696
  const verb = requests.length === 1 ? "is" : "are";
@@ -6029,14 +6698,14 @@ function describeOutstanding(requests, now) {
6029
6698
  }
6030
6699
  function describeLastResponse(lastResponse, now) {
6031
6700
  if (!lastResponse) return "No response has been received this session.";
6032
- return `Last response received ${formatDuration(now - lastResponse.receivedAt)} ago (${lastResponse.method}).`;
6701
+ return `Last response received ${formatDuration$1(now - lastResponse.receivedAt)} ago (${lastResponse.method}).`;
6033
6702
  }
6034
6703
  function describeStream(stream, now) {
6035
6704
  if (!stream) return void 0;
6036
6705
  const endpoint = describeStreamEndpoint(stream.url);
6037
6706
  const events = plural(stream.eventCount, "event");
6038
- if (stream.closedAt !== void 0) return `Notification stream (${endpoint}) closed ${formatDuration(now - stream.closedAt)} ago after ${formatDuration(stream.closedAt - stream.openedAt)}, ${events} delivered.`;
6039
- return `Notification stream (${endpoint}) open for ${formatDuration(now - stream.openedAt)}, ${events} delivered.`;
6707
+ if (stream.closedAt !== void 0) return `Notification stream (${endpoint}) closed ${formatDuration$1(now - stream.closedAt)} ago after ${formatDuration$1(stream.closedAt - stream.openedAt)}, ${events} delivered.`;
6708
+ return `Notification stream (${endpoint}) open for ${formatDuration$1(now - stream.openedAt)}, ${events} delivered.`;
6040
6709
  }
6041
6710
  function describeConnectionDiagnostics(diagnostics) {
6042
6711
  const now = diagnostics.capturedAt;
@@ -6053,7 +6722,7 @@ function annotateRequestTimeout(err, method, diagnostics) {
6053
6722
  method,
6054
6723
  diagnostics
6055
6724
  };
6056
- const message = `Request timed out after ${formatDuration(err.data.timeout)} (${method}). ${describeConnectionDiagnostics(diagnostics)}`;
6725
+ const message = `Request timed out after ${formatDuration$1(err.data.timeout)} (${method}). ${describeConnectionDiagnostics(diagnostics)}`;
6057
6726
  const annotated = new SdkError(SdkErrorCode.RequestTimeout, message, data);
6058
6727
  annotated.cause = err;
6059
6728
  return annotated;
@@ -6123,7 +6792,7 @@ function attachRetryAfter(err, retryAfter) {
6123
6792
  err.data.retryAfter = retryAfter;
6124
6793
  }
6125
6794
  function describeRetry(retryAfter, retryAfterMs) {
6126
- if (retryAfterMs !== void 0) return `The server asked to retry after ${formatDuration(retryAfterMs)}.`;
6795
+ if (retryAfterMs !== void 0) return `The server asked to retry after ${formatDuration$1(retryAfterMs)}.`;
6127
6796
  if (retryAfter !== void 0) return `The server sent an unparseable Retry-After (${retryAfter}).`;
6128
6797
  return "The server sent no Retry-After header.";
6129
6798
  }
@@ -6168,8 +6837,7 @@ function applyAuthorizationParams(authorizationUrl, params) {
6168
6837
  for (const [key, value] of applicable) merged.searchParams.set(key.trim(), value);
6169
6838
  return merged;
6170
6839
  }
6171
- //#endregion
6172
- //#region ../../core/auth/scopes.ts
6840
+ // ../../core/auth/scopes.ts
6173
6841
  const computeScopeUnion$1 = computeScopeUnion;
6174
6842
  const isStrictScopeSuperset$1 = isStrictScopeSuperset;
6175
6843
  const OFFLINE_ACCESS_SCOPE = "offline_access";
@@ -6197,8 +6865,7 @@ function resolveEffectiveGrantedScope(storedScope, tokenScope) {
6197
6865
  if (granted) return granted;
6198
6866
  return computeScopeUnion$1(storedScope, tokenScope);
6199
6867
  }
6200
- //#endregion
6201
- //#region ../../core/auth/providers.ts
6868
+ // ../../core/auth/providers.ts
6202
6869
  var MutableRedirectUrlProvider = class {
6203
6870
  redirectUrl = "";
6204
6871
  getRedirectUrl() {
@@ -6429,8 +7096,7 @@ var BaseOAuthClientProvider = class {
6429
7096
  }
6430
7097
  }
6431
7098
  };
6432
- //#endregion
6433
- //#region ../../core/auth/types.ts
7099
+ // ../../core/auth/types.ts
6434
7100
  function authProtocolFromEnterpriseManaged(enterpriseManaged) {
6435
7101
  return enterpriseManaged ? "ema" : "standard";
6436
7102
  }
@@ -6451,8 +7117,7 @@ const EMPTY_OAUTH_FLOW_STATE = {
6451
7117
  statusMessage: null,
6452
7118
  validationError: null
6453
7119
  };
6454
- //#endregion
6455
- //#region ../../core/auth/mcpAuth.ts
7120
+ // ../../core/auth/mcpAuth.ts
6456
7121
  async function mcpAuth(provider, options) {
6457
7122
  if (options.forceReauthorization && options.authorizationCode !== void 0) throw new Error("forceReauthorization cannot be combined with authorizationCode");
6458
7123
  return auth(provider, {
@@ -6723,8 +7388,7 @@ async function runPlan(plan, params) {
6723
7388
  }
6724
7389
  return aggregateOutcomes(outcomes);
6725
7390
  }
6726
- //#endregion
6727
- //#region ../../core/auth/ema/clientConfigError.ts
7391
+ // ../../core/auth/ema/clientConfigError.ts
6728
7392
  function emaClientNotConfiguredMessage(reason) {
6729
7393
  if (reason === "disabled") return "This server uses enterprise-managed authorization, but Enterprise IdP is turned off in Client Settings. Open Client Settings, enable \"Enterprise IdP configuration\", then try connecting again.";
6730
7394
  return "This server uses enterprise-managed authorization, but the Inspector client IdP is not configured. Open Client Settings, enable Enterprise IdP, and set issuer, client ID, and client secret.";
@@ -6740,12 +7404,10 @@ var EmaClientNotConfiguredError = class extends Error {
6740
7404
  function isEmaClientNotConfiguredError(err) {
6741
7405
  return err instanceof EmaClientNotConfiguredError;
6742
7406
  }
6743
- //#endregion
6744
- //#region ../../core/auth/ema/constants.ts
7407
+ // ../../core/auth/ema/constants.ts
6745
7408
  const GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";
6746
7409
  const IDP_OIDC_SCOPES = "openid offline_access";
6747
- //#endregion
6748
- //#region ../../core/auth/ema/jwt.ts
7410
+ // ../../core/auth/ema/jwt.ts
6749
7411
  function decodeBase64Url(segment) {
6750
7412
  const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
6751
7413
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
@@ -6772,8 +7434,19 @@ function isJwtFormat(token) {
6772
7434
  const parts = token.split(".");
6773
7435
  return parts.length === 3 && parts[0].length > 0 && parts[1].length > 0 && parts[2] !== void 0;
6774
7436
  }
6775
- //#endregion
6776
- //#region ../../core/auth/ema/storage.ts
7437
+ function decodeJwtPayload(token) {
7438
+ if (!isJwtFormat(token)) return void 0;
7439
+ const parts = token.split(".");
7440
+ try {
7441
+ return {
7442
+ header: JSON.parse(decodeBase64Url(parts[0])),
7443
+ payload: JSON.parse(decodeBase64Url(parts[1]))
7444
+ };
7445
+ } catch {
7446
+ return;
7447
+ }
7448
+ }
7449
+ // ../../core/auth/ema/storage.ts
6777
7450
  function normalizeIdpIssuer(issuer) {
6778
7451
  return issuer.replace(/\/$/, "");
6779
7452
  }
@@ -6781,8 +7454,7 @@ const IDP_OAUTH_KEY_PREFIX = "ema-idp:";
6781
7454
  function idpOAuthStorageKey(issuer) {
6782
7455
  return `${IDP_OAUTH_KEY_PREFIX}${normalizeIdpIssuer(issuer)}`;
6783
7456
  }
6784
- //#endregion
6785
- //#region ../../core/auth/ema/tokenEndpoint.ts
7457
+ // ../../core/auth/ema/tokenEndpoint.ts
6786
7458
  async function parseOAuthTokenErrorResponse(response, step) {
6787
7459
  let body;
6788
7460
  try {
@@ -6826,8 +7498,7 @@ async function postOAuthTokenRequest(tokenUrl, body, metadata, clientInformation
6826
7498
  body
6827
7499
  });
6828
7500
  }
6829
- //#endregion
6830
- //#region ../../core/auth/ema/idpOidc.ts
7501
+ // ../../core/auth/ema/idpOidc.ts
6831
7502
  function idpClientInformation(idp) {
6832
7503
  return {
6833
7504
  client_id: idp.clientId,
@@ -6950,8 +7621,7 @@ async function getValidIdToken(params) {
6950
7621
  return;
6951
7622
  }
6952
7623
  }
6953
- //#endregion
6954
- //#region ../../core/auth/discovery.ts
7624
+ // ../../core/auth/discovery.ts
6955
7625
  function serverUrlAsAuthorizationServer(serverUrl) {
6956
7626
  try {
6957
7627
  const url = new URL(serverUrl);
@@ -6993,8 +7663,7 @@ async function discoverAuthorizationServerMetadataFromCandidates(candidates, dis
6993
7663
  async function discoverAuthorizationServerMetadataForServer(serverUrl, resourceMetadata, fetchFn) {
6994
7664
  return (await discoverAuthorizationServerMetadataFromCandidates(getAuthorizationServerUrlCandidates(serverUrl, resourceMetadata), (candidate) => discoverAuthorizationServerMetadata(candidate, { fetchFn })))?.metadata;
6995
7665
  }
6996
- //#endregion
6997
- //#region ../../core/auth/ema/resourceContext.ts
7666
+ // ../../core/auth/ema/resourceContext.ts
6998
7667
  function resolveEmaScopes(resourceMetadata, configuredScope) {
6999
7668
  const trimmed = configuredScope?.trim();
7000
7669
  if (trimmed) return trimmed;
@@ -7027,8 +7696,7 @@ async function discoverResourceAsMetadata(resourceAsUrl, fetchFn) {
7027
7696
  if (!metadata) throw new Error("Failed to discover resource authorization server metadata");
7028
7697
  return metadata;
7029
7698
  }
7030
- //#endregion
7031
- //#region ../../core/auth/ema/wire.ts
7699
+ // ../../core/auth/ema/wire.ts
7032
7700
  async function exchangeIdJag(params) {
7033
7701
  const issuer = normalizeIdpIssuer(params.idp.issuer);
7034
7702
  const resource = params.resource.trim();
@@ -7072,8 +7740,7 @@ async function redeemIdJagForAccessToken(params) {
7072
7740
  if (!response.ok) throw await parseOAuthTokenErrorResponse(response, "EMA leg 3 (resource AS JWT bearer grant)");
7073
7741
  return OAuthTokensSchema.parse(await response.json());
7074
7742
  }
7075
- //#endregion
7076
- //#region ../../core/auth/ema/emaFlow.ts
7743
+ // ../../core/auth/ema/emaFlow.ts
7077
7744
  function wrapEmaMintError(err) {
7078
7745
  const message = err instanceof Error ? err.message : String(err);
7079
7746
  return new Error(`EMA legs 2–3 (resource token mint): ${message}`, { cause: err });
@@ -7173,8 +7840,7 @@ async function refreshEmaResourceTokens(config) {
7173
7840
  await saveMintedTokens(config, minted);
7174
7841
  return minted.tokens;
7175
7842
  }
7176
- //#endregion
7177
- //#region ../../core/auth/ema/idpSession.ts
7843
+ // ../../core/auth/ema/idpSession.ts
7178
7844
  async function getEmaIdpLoginState(storage, issuer) {
7179
7845
  const normalized = normalizeIdpIssuer(issuer);
7180
7846
  if (!normalized) return "none";
@@ -7184,8 +7850,7 @@ async function getEmaIdpLoginState(storage, issuer) {
7184
7850
  if (session.refreshToken) return "logged_in";
7185
7851
  return "expired";
7186
7852
  }
7187
- //#endregion
7188
- //#region ../../core/auth/connection-state.ts
7853
+ // ../../core/auth/connection-state.ts
7189
7854
  function isAccessTokenUsable$1(tokens) {
7190
7855
  if (!tokens?.access_token) return false;
7191
7856
  return !isJwtExpired(tokens.access_token);
@@ -7268,8 +7933,7 @@ async function hasPersistedOAuthServerState(storage, serverUrl) {
7268
7933
  function protocolFromOAuthConfig(config) {
7269
7934
  return authProtocolFromEnterpriseManaged(config.enterpriseManaged);
7270
7935
  }
7271
- //#endregion
7272
- //#region ../../core/auth/cimd.ts
7936
+ // ../../core/auth/cimd.ts
7273
7937
  async function ensureCimdClientRegistration(params) {
7274
7938
  const clientMetadataUrl = params.provider.clientMetadataUrl?.trim();
7275
7939
  if (!clientMetadataUrl) return;
@@ -7295,8 +7959,7 @@ async function ensureCimdClientRegistration(params) {
7295
7959
  ...issuer && { issuer }
7296
7960
  });
7297
7961
  }
7298
- //#endregion
7299
- //#region ../../core/auth/ema/transportProvider.ts
7962
+ // ../../core/auth/ema/transportProvider.ts
7300
7963
  function isAccessTokenUsable(tokens, skewMs = 6e4) {
7301
7964
  if (!tokens.access_token) return false;
7302
7965
  return !isJwtExpired(tokens.access_token, skewMs);
@@ -7356,8 +8019,7 @@ var EmaTransportOAuthProvider = class {
7356
8019
  return this.inner.codeVerifier();
7357
8020
  }
7358
8021
  };
7359
- //#endregion
7360
- //#region ../../core/auth/oauthUx.ts
8022
+ // ../../core/auth/oauthUx.ts
7361
8023
  function isStandardOAuthStepUp(challenge, options) {
7362
8024
  return challenge.reason === "insufficient_scope" && !options?.enterpriseManaged;
7363
8025
  }
@@ -7429,8 +8091,7 @@ function issuerBindingFailureCopy(failure, options) {
7429
8091
  })
7430
8092
  };
7431
8093
  }
7432
- //#endregion
7433
- //#region ../../core/mcp/oauthManager.ts
8094
+ // ../../core/mcp/oauthManager.ts
7434
8095
  var OAuthManager = class {
7435
8096
  params;
7436
8097
  oauthConfig;
@@ -7913,8 +8574,7 @@ var OAuthManager = class {
7913
8574
  return provider;
7914
8575
  }
7915
8576
  };
7916
- //#endregion
7917
- //#region ../../core/mcp/remote/types.ts
8577
+ // ../../core/mcp/remote/types.ts
7918
8578
  function oauthTokensToRemoteAuthState(tokens) {
7919
8579
  return { oauthTokens: {
7920
8580
  access_token: tokens.access_token,
@@ -7925,8 +8585,7 @@ function oauthTokensToRemoteAuthState(tokens) {
7925
8585
  id_token: tokens.id_token
7926
8586
  } };
7927
8587
  }
7928
- //#endregion
7929
- //#region ../../core/mcp/remote/progressToken.ts
8588
+ // ../../core/mcp/remote/progressToken.ts
7930
8589
  function progressTokenOf(message) {
7931
8590
  if ("method" in message && message.method === "notifications/progress" && "params" in message && typeof message.params === "object" && message.params !== null) {
7932
8591
  const parsed = ProgressTokenSchema.safeParse(message.params.progressToken);
@@ -7939,8 +8598,7 @@ function waitForProgressToken(waits, token) {
7939
8598
  const numeric = Number(token);
7940
8599
  return Number.isSafeInteger(numeric) ? waits.get(numeric) : void 0;
7941
8600
  }
7942
- //#endregion
7943
- //#region ../../core/mcp/remote/remoteClientTransport.ts
8601
+ // ../../core/mcp/remote/remoteClientTransport.ts
7944
8602
  const DEFAULT_SSE_RESPONSE_TIMEOUT_MS = 6e4;
7945
8603
  function requestIdForMessage(message) {
7946
8604
  if ("method" in message && "id" in message && message.id !== null && message.id !== void 0) {
@@ -8084,7 +8742,8 @@ var RemoteClientTransport = class {
8084
8742
  const body = {
8085
8743
  config: this.config,
8086
8744
  ...authState && { authState },
8087
- ...this.options.settings && { settings: this.options.settings }
8745
+ ...this.options.settings && { settings: this.options.settings },
8746
+ ...this.options.serverName && { serverName: this.options.serverName }
8088
8747
  };
8089
8748
  const res = await this.fetchFn(`${this.baseUrl}/api/mcp/connect`, {
8090
8749
  method: "POST",
@@ -8333,6 +8992,16 @@ var RemoteClientTransport = class {
8333
8992
  }
8334
8993
  return await res.json();
8335
8994
  }
8995
+ releaseOnPageHide() {
8996
+ if (!this._sessionId) return false;
8997
+ this.fetchFn(`${this.baseUrl}/api/mcp/disconnect`, {
8998
+ method: "POST",
8999
+ headers: this.headers,
9000
+ body: JSON.stringify({ sessionId: this._sessionId }),
9001
+ keepalive: true
9002
+ }).catch(() => {});
9003
+ return true;
9004
+ }
8336
9005
  async close() {
8337
9006
  if (this.closed) return;
8338
9007
  this.closed = true;
@@ -8360,8 +9029,25 @@ var RemoteClientTransport = class {
8360
9029
  onerror;
8361
9030
  onmessage;
8362
9031
  };
8363
- //#endregion
8364
- //#region ../../core/mcp/inspectorClient.ts
9032
+ // ../../core/mcp/sessionTermination.ts
9033
+ function canTerminateSession(transport) {
9034
+ return typeof transport === "object" && transport !== null && "terminateSession" in transport && typeof transport.terminateSession === "function";
9035
+ }
9036
+ const SESSION_TERMINATE_TIMEOUT_MS = 3e3;
9037
+ async function terminateSessionBestEffort(transport, timeoutMs = SESSION_TERMINATE_TIMEOUT_MS) {
9038
+ if (!canTerminateSession(transport) || !transport.sessionId) return false;
9039
+ let timer;
9040
+ const timedOut = new Promise((resolve) => {
9041
+ timer = setTimeout(() => resolve(false), timeoutMs);
9042
+ });
9043
+ const terminated = new Promise((resolve) => resolve(transport.terminateSession())).then(() => true, () => false);
9044
+ try {
9045
+ return await Promise.race([terminated, timedOut]);
9046
+ } finally {
9047
+ clearTimeout(timer);
9048
+ }
9049
+ }
9050
+ // ../../core/mcp/inspectorClient.ts
8365
9051
  const corePackageJson = {
8366
9052
  name: "mcp-inspector",
8367
9053
  version: "0.0.0"
@@ -8490,6 +9176,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
8490
9176
  transportClientFactory;
8491
9177
  fetchFn;
8492
9178
  effectiveAuthFetch;
9179
+ fetchRefusals = [];
8493
9180
  sessionId;
8494
9181
  transportConfig;
8495
9182
  directAuthRecoveryActive = null;
@@ -8525,8 +9212,9 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
8525
9212
  resources: options.listChangedNotifications?.resources ?? true,
8526
9213
  prompts: options.listChangedNotifications?.prompts ?? true
8527
9214
  };
8528
- const transportBase = this.fetchFn ?? fetch;
8529
- const oauthBase = options.environment.oauthFetch;
9215
+ const reportRefusal = (refusal) => this.recordFetchRefusal(refusal);
9216
+ const transportBase = withFetchRefusalReporting(this.fetchFn ?? fetch, reportRefusal);
9217
+ const oauthBase = options.environment.oauthFetch && withFetchRefusalReporting(options.environment.oauthFetch, reportRefusal);
8530
9218
  const isMcpEndpoint = exemptMcpEndpoint(() => this.getServerUrl(), () => this.transportConfig?.type === "sse");
8531
9219
  const getOverrides = () => this.oauthManager?.getEndpointOverrides();
8532
9220
  const withOverrides = withOAuthEndpointOverrides(oauthBase ? routeOAuthRequests(transportBase, oauthBase, isMcpEndpoint) : transportBase, getOverrides);
@@ -9063,6 +9751,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9063
9751
  while (handlers?.size !== void 0 && handlers.size > 0 && Date.now() < deadline) await new Promise((r) => setTimeout(r, 10));
9064
9752
  }
9065
9753
  await this.closeTaskSessionBestEffort();
9754
+ await terminateSessionBestEffort(this.baseTransport);
9066
9755
  try {
9067
9756
  await this.client.close();
9068
9757
  } catch {}
@@ -9105,6 +9794,14 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9105
9794
  this.dispatchTypedEvent("excludedToolsChange", this.excludedTools);
9106
9795
  this.dispatchTypedEvent("malformedListItemsChange", []);
9107
9796
  }
9797
+ getFetchRefusals() {
9798
+ return [...this.fetchRefusals];
9799
+ }
9800
+ recordFetchRefusal(refusal) {
9801
+ if (this.fetchRefusals.some((r) => r.url === refusal.url && r.reason === refusal.reason)) return;
9802
+ this.fetchRefusals = [...this.fetchRefusals, refusal].slice(-20);
9803
+ this.dispatchTypedEvent("fetchRefused", refusal);
9804
+ }
9108
9805
  getAppRendererClient() {
9109
9806
  if (!this.client || this.status !== "connected") return null;
9110
9807
  return this.client;
@@ -9270,7 +9967,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9270
9967
  params: request.params,
9271
9968
  signal: controller.signal
9272
9969
  });
9273
- this.outputValidator ??= new AjvJsonSchemaValidator();
9970
+ this.outputValidator ??= new LinearPatternJsonSchemaValidator();
9274
9971
  const invalid = validateAppElicitResult(this.outputValidator, request.params, result);
9275
9972
  if (invalid) {
9276
9973
  this.logger.warn({
@@ -9869,7 +10566,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9869
10566
  });
9870
10567
  }
9871
10568
  validateToolOutput(tool, result) {
9872
- this.outputValidator ??= new AjvJsonSchemaValidator();
10569
+ this.outputValidator ??= new LinearPatternJsonSchemaValidator();
9873
10570
  return validateToolOutput(this.outputValidator, tool, result);
9874
10571
  }
9875
10572
  cancelPendingTaskInput(taskId) {
@@ -10716,6 +11413,10 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
10716
11413
  getRemoteBackendSessionId() {
10717
11414
  if (this.baseTransport instanceof RemoteClientTransport) return this.baseTransport.getRemoteBackendSessionId();
10718
11415
  }
11416
+ releaseRemoteSessionOnPageHide() {
11417
+ if (this.baseTransport instanceof RemoteClientTransport) return this.baseTransport.releaseOnPageHide();
11418
+ return false;
11419
+ }
10719
11420
  async resumeAfterOAuth(authorizationCode, options) {
10720
11421
  await this.completeOAuthFlow(authorizationCode, options?.iss, options?.state);
10721
11422
  const remoteSessionId = options?.remoteSessionId;
@@ -10753,8 +11454,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
10753
11454
  return this.oauthManager.getOAuthState();
10754
11455
  }
10755
11456
  };
10756
- //#endregion
10757
- //#region ../../core/mcp/state/managedListState.ts
11457
+ // ../../core/mcp/state/managedListState.ts
10758
11458
  var ManagedListState = class extends TypedEventTarget {
10759
11459
  items = [];
10760
11460
  client = null;
@@ -10899,8 +11599,7 @@ var ManagedListState = class extends TypedEventTarget {
10899
11599
  this.loaded = false;
10900
11600
  }
10901
11601
  };
10902
- //#endregion
10903
- //#region ../../core/mcp/state/managedToolsState.ts
11602
+ // ../../core/mcp/state/managedToolsState.ts
10904
11603
  var ManagedToolsState = class extends ManagedListState {
10905
11604
  constructor(client, debounceMs = 250) {
10906
11605
  super(client, {
@@ -10923,8 +11622,7 @@ var ManagedToolsState = class extends ManagedListState {
10923
11622
  return this.getItems();
10924
11623
  }
10925
11624
  };
10926
- //#endregion
10927
- //#region ../../core/mcp/state/messageLogState.ts
11625
+ // ../../core/mcp/state/messageLogState.ts
10928
11626
  var MessageLogState = class extends TypedEventTarget {
10929
11627
  messages = [];
10930
11628
  pendingRequestEntries = /* @__PURE__ */ new Map();
@@ -10941,6 +11639,16 @@ var MessageLogState = class extends TypedEventTarget {
10941
11639
  this.dispatchTypedEvent("message", entry);
10942
11640
  this.dispatchTypedEvent("messagesChange", this.getMessages());
10943
11641
  };
11642
+ const replaceEntry = (entry, changes) => {
11643
+ const index = this.messages.lastIndexOf(entry);
11644
+ if (index < 0) return void 0;
11645
+ const updated = {
11646
+ ...entry,
11647
+ ...changes
11648
+ };
11649
+ this.messages[index] = updated;
11650
+ return updated;
11651
+ };
10944
11652
  const onMessage = (event) => {
10945
11653
  const entry = event.detail;
10946
11654
  if (entry.direction === "request") {
@@ -10954,9 +11662,12 @@ var MessageLogState = class extends TypedEventTarget {
10954
11662
  const requestEntry = messageId !== void 0 ? this.pendingRequestEntries.get(messageId) : void 0;
10955
11663
  if (requestEntry) {
10956
11664
  this.pendingRequestEntries.delete(messageId);
10957
- requestEntry.response = entry.message;
10958
- requestEntry.duration = entry.timestamp.getTime() - requestEntry.timestamp.getTime();
10959
- this.dispatchTypedEvent("message", requestEntry);
11665
+ const updated = replaceEntry(requestEntry, {
11666
+ response: entry.message,
11667
+ duration: entry.timestamp.getTime() - requestEntry.timestamp.getTime()
11668
+ });
11669
+ if (!updated) return;
11670
+ this.dispatchTypedEvent("message", updated);
10960
11671
  this.dispatchTypedEvent("messagesChange", this.getMessages());
10961
11672
  return;
10962
11673
  }
@@ -10970,8 +11681,12 @@ var MessageLogState = class extends TypedEventTarget {
10970
11681
  if (entry.message.id !== id) continue;
10971
11682
  if (entry.direction === "notification") continue;
10972
11683
  if (entry.direction === "request" && !entry.response) continue;
10973
- entry.clientError = reason;
10974
- this.dispatchTypedEvent("message", entry);
11684
+ const updated = {
11685
+ ...entry,
11686
+ clientError: reason
11687
+ };
11688
+ this.messages[i] = updated;
11689
+ this.dispatchTypedEvent("message", updated);
10975
11690
  this.dispatchTypedEvent("messagesChange", this.getMessages());
10976
11691
  return;
10977
11692
  }
@@ -10981,9 +11696,12 @@ var MessageLogState = class extends TypedEventTarget {
10981
11696
  const requestEntry = this.pendingRequestEntries.get(id);
10982
11697
  if (!requestEntry) return;
10983
11698
  this.pendingRequestEntries.delete(id);
10984
- requestEntry.clientError = reason;
10985
- requestEntry.duration = Date.now() - requestEntry.timestamp.getTime();
10986
- this.dispatchTypedEvent("message", requestEntry);
11699
+ const updated = replaceEntry(requestEntry, {
11700
+ clientError: reason,
11701
+ duration: Date.now() - requestEntry.timestamp.getTime()
11702
+ });
11703
+ if (!updated) return;
11704
+ this.dispatchTypedEvent("message", updated);
10987
11705
  this.dispatchTypedEvent("messagesChange", this.getMessages());
10988
11706
  };
10989
11707
  const onStatusChange = () => {
@@ -11027,8 +11745,7 @@ var MessageLogState = class extends TypedEventTarget {
11027
11745
  this.pendingRequestEntries.clear();
11028
11746
  }
11029
11747
  };
11030
- //#endregion
11031
- //#region ../../core/mcp/state/fetchRequestLogState.ts
11748
+ // ../../core/mcp/state/fetchRequestLogState.ts
11032
11749
  var FetchRequestLogState = class extends TypedEventTarget {
11033
11750
  fetchRequests = [];
11034
11751
  client = null;
@@ -11147,8 +11864,7 @@ var FetchRequestLogState = class extends TypedEventTarget {
11147
11864
  this.fetchRequests = [];
11148
11865
  }
11149
11866
  };
11150
- //#endregion
11151
- //#region ../../core/mcp/state/stderrLogState.ts
11867
+ // ../../core/mcp/state/stderrLogState.ts
11152
11868
  var StderrLogState = class extends TypedEventTarget {
11153
11869
  stderrLogs = [];
11154
11870
  client = null;
@@ -11185,8 +11901,7 @@ var StderrLogState = class extends TypedEventTarget {
11185
11901
  this.stderrLogs = [];
11186
11902
  }
11187
11903
  };
11188
- //#endregion
11189
- //#region ../../core/mcp/state/managedResourcesState.ts
11904
+ // ../../core/mcp/state/managedResourcesState.ts
11190
11905
  var ManagedResourcesState = class extends ManagedListState {
11191
11906
  constructor(client, debounceMs = 250) {
11192
11907
  super(client, {
@@ -11209,8 +11924,7 @@ var ManagedResourcesState = class extends ManagedListState {
11209
11924
  return this.getItems();
11210
11925
  }
11211
11926
  };
11212
- //#endregion
11213
- //#region ../../core/mcp/state/managedResourceTemplatesState.ts
11927
+ // ../../core/mcp/state/managedResourceTemplatesState.ts
11214
11928
  var ManagedResourceTemplatesState = class extends ManagedListState {
11215
11929
  constructor(client, debounceMs = 250) {
11216
11930
  super(client, {
@@ -11233,8 +11947,7 @@ var ManagedResourceTemplatesState = class extends ManagedListState {
11233
11947
  return this.getItems();
11234
11948
  }
11235
11949
  };
11236
- //#endregion
11237
- //#region ../../core/mcp/state/managedPromptsState.ts
11950
+ // ../../core/mcp/state/managedPromptsState.ts
11238
11951
  var ManagedPromptsState = class extends ManagedListState {
11239
11952
  constructor(client, debounceMs = 250) {
11240
11953
  super(client, {
@@ -11257,8 +11970,7 @@ var ManagedPromptsState = class extends ManagedListState {
11257
11970
  return this.getItems();
11258
11971
  }
11259
11972
  };
11260
- //#endregion
11261
- //#region ../../core/mcp/state/mergeTaskIntoList.ts
11973
+ // ../../core/mcp/state/mergeTaskIntoList.ts
11262
11974
  function mergeTaskIntoList(tasks, taskId, task) {
11263
11975
  const normalized = {
11264
11976
  ...task,
@@ -11271,8 +11983,7 @@ function mergeTaskIntoList(tasks, taskId, task) {
11271
11983
  next[idx] = normalized;
11272
11984
  return next;
11273
11985
  }
11274
- //#endregion
11275
- //#region ../../core/mcp/state/managedRequestorTasksState.ts
11986
+ // ../../core/mcp/state/managedRequestorTasksState.ts
11276
11987
  const MAX_PAGES = 100;
11277
11988
  const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
11278
11989
  "completed",
@@ -11407,8 +12118,7 @@ var ManagedRequestorTasksState = class extends TypedEventTarget {
11407
12118
  this.cancelledTaskIds.clear();
11408
12119
  }
11409
12120
  };
11410
- //#endregion
11411
- //#region ../../core/mcp/state/resourceSubscriptionsState.ts
12121
+ // ../../core/mcp/state/resourceSubscriptionsState.ts
11412
12122
  var ResourceSubscriptionsState = class extends TypedEventTarget {
11413
12123
  subscribedUris = [];
11414
12124
  lastUpdatedByUri = /* @__PURE__ */ new Map();
@@ -11497,8 +12207,7 @@ var ResourceSubscriptionsState = class extends TypedEventTarget {
11497
12207
  this.streamState = INACTIVE_SUBSCRIPTION_STREAM_STATE;
11498
12208
  }
11499
12209
  };
11500
- //#endregion
11501
- //#region ../../core/mcp/state/managedSkillsState.ts
12210
+ // ../../core/mcp/state/managedSkillsState.ts
11502
12211
  const REPEATED_CURSOR_MESSAGE = "Server repeated a pagination cursor in skills/list; stopped to avoid an infinite walk.";
11503
12212
  const SKILLS_MAX_PAGES = 64;
11504
12213
  const SKILLS_PAGE_LIMIT_MESSAGE = `skills/list exceeded ${SKILLS_MAX_PAGES} pages without the server's pagination converging`;
@@ -11607,17 +12316,45 @@ var ManagedSkillsState = class extends TypedEventTarget {
11607
12316
  this.error = null;
11608
12317
  }
11609
12318
  };
11610
- //#endregion
11611
- //#region ../../core/react/useStoreSnapshot.ts
11612
- function useStoreSnapshot(store, event, read, whenAbsent) {
12319
+ // ../../core/react/notifyScheduler.ts
12320
+ function coalesce(onChange, schedule) {
12321
+ let cancelPending = null;
12322
+ return {
12323
+ notify: () => {
12324
+ if (cancelPending) return;
12325
+ cancelPending = schedule(() => {
12326
+ cancelPending = null;
12327
+ onChange();
12328
+ });
12329
+ },
12330
+ cancel: () => {
12331
+ cancelPending?.();
12332
+ cancelPending = null;
12333
+ }
12334
+ };
12335
+ }
12336
+ // ../../core/react/useStoreSnapshot.ts
12337
+ function useStoreSnapshot(store, event, read, whenAbsent, schedule) {
11613
12338
  const cache = useRef(null);
11614
12339
  const subscribe = useCallback((onStoreChange) => {
11615
12340
  if (!store) return () => {};
11616
- store.addEventListener(event, onStoreChange);
12341
+ if (!schedule) {
12342
+ store.addEventListener(event, onStoreChange);
12343
+ return () => {
12344
+ store.removeEventListener(event, onStoreChange);
12345
+ };
12346
+ }
12347
+ const { notify, cancel } = coalesce(onStoreChange, schedule);
12348
+ store.addEventListener(event, notify);
11617
12349
  return () => {
11618
- store.removeEventListener(event, onStoreChange);
12350
+ store.removeEventListener(event, notify);
12351
+ cancel();
11619
12352
  };
11620
- }, [store, event]);
12353
+ }, [
12354
+ store,
12355
+ event,
12356
+ schedule
12357
+ ]);
11621
12358
  const getSnapshot = useCallback(() => {
11622
12359
  const revision = store ? store.getEventRevision(event) : 0;
11623
12360
  const cached = cache.current;
@@ -11640,8 +12377,7 @@ function useStoreSnapshot(store, event, read, whenAbsent) {
11640
12377
  ]);
11641
12378
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
11642
12379
  }
11643
- //#endregion
11644
- //#region ../../core/react/useInspectorClient.ts
12380
+ // ../../core/react/useInspectorClient.ts
11645
12381
  const EMPTY_CLIENT_CAPABILITIES = Object.freeze({});
11646
12382
  const NO_EXCLUDED_TOOLS = [];
11647
12383
  const NO_MALFORMED_LIST_ITEMS = [];
@@ -11659,7 +12395,7 @@ const readDiscoverResult = (client) => client.getDiscoverResult();
11659
12395
  const readExcludedTools = (client) => client.getExcludedTools();
11660
12396
  const readMalformedListItems = (client) => client.getMalformedListItems();
11661
12397
  const readConnectionDiagnostics = (client) => client.getConnectionDiagnostics?.() ?? NO_CONNECTION_DIAGNOSTICS;
11662
- function useInspectorClient(inspectorClient) {
12398
+ function useInspectorClient(inspectorClient, diagnosticsSchedule) {
11663
12399
  const status = useStoreSnapshot(inspectorClient, "statusChange", readStatus, "disconnected");
11664
12400
  const capabilities = useStoreSnapshot(inspectorClient, "capabilitiesChange", readCapabilities, void 0);
11665
12401
  const serverInfo = useStoreSnapshot(inspectorClient, "serverInfoChange", readServerInfo, void 0);
@@ -11669,7 +12405,7 @@ function useInspectorClient(inspectorClient) {
11669
12405
  const discoverResult = useStoreSnapshot(inspectorClient, "discoverResultChange", readDiscoverResult, void 0);
11670
12406
  const excludedTools = useStoreSnapshot(inspectorClient, "excludedToolsChange", readExcludedTools, NO_EXCLUDED_TOOLS);
11671
12407
  const malformedListItems = useStoreSnapshot(inspectorClient, "malformedListItemsChange", readMalformedListItems, NO_MALFORMED_LIST_ITEMS);
11672
- const connectionDiagnostics = useStoreSnapshot(inspectorClient, "connectionDiagnosticsChange", readConnectionDiagnostics, NO_CONNECTION_DIAGNOSTICS);
12408
+ const connectionDiagnostics = useStoreSnapshot(inspectorClient, "connectionDiagnosticsChange", readConnectionDiagnostics, NO_CONNECTION_DIAGNOSTICS, diagnosticsSchedule);
11673
12409
  const [errorState, setErrorState] = useState({ client: inspectorClient });
11674
12410
  if (errorState.client !== inspectorClient) setErrorState({ client: inspectorClient });
11675
12411
  const lastError = errorState.client === inspectorClient ? errorState.message : void 0;
@@ -11717,8 +12453,7 @@ function useInspectorClient(inspectorClient) {
11717
12453
  disconnect
11718
12454
  };
11719
12455
  }
11720
- //#endregion
11721
- //#region ../../core/react/useListError.ts
12456
+ // ../../core/react/useListError.ts
11722
12457
  function useListError(state) {
11723
12458
  const subscribe = useCallback((onStoreChange) => {
11724
12459
  if (!state) return () => {};
@@ -11731,8 +12466,7 @@ function useListError(state) {
11731
12466
  const getSnapshot = useCallback(() => state?.getError() ?? null, [state]);
11732
12467
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
11733
12468
  }
11734
- //#endregion
11735
- //#region ../../core/react/useManagedTools.ts
12469
+ // ../../core/react/useManagedTools.ts
11736
12470
  const NO_TOOLS = [];
11737
12471
  const readTools = (state) => state.getTools();
11738
12472
  const readListChanged$2 = (state) => state.getListChanged();
@@ -11756,8 +12490,18 @@ function useManagedTools(client, managedToolsState) {
11756
12490
  }, [managedToolsState])
11757
12491
  };
11758
12492
  }
11759
- //#endregion
11760
- //#region ../../core/react/useManagedResources.ts
12493
+ // ../../core/mcp/toolOrder.ts
12494
+ const toolLabelCollator = new Intl.Collator(void 0, {
12495
+ sensitivity: "base",
12496
+ numeric: true
12497
+ });
12498
+ function compareToolLabels(a, b) {
12499
+ return toolLabelCollator.compare(a, b);
12500
+ }
12501
+ function compareToolsByName(a, b) {
12502
+ return compareToolLabels(a.name, b.name);
12503
+ }
12504
+ // ../../core/react/useManagedResources.ts
11761
12505
  const NO_RESOURCES = [];
11762
12506
  const readResources = (state) => state.getResources();
11763
12507
  const readListChanged$1 = (state) => state.getListChanged();
@@ -11781,8 +12525,7 @@ function useManagedResources(client, managedResourcesState) {
11781
12525
  }, [managedResourcesState])
11782
12526
  };
11783
12527
  }
11784
- //#endregion
11785
- //#region ../../core/react/useManagedResourceTemplates.ts
12528
+ // ../../core/react/useManagedResourceTemplates.ts
11786
12529
  const NO_RESOURCE_TEMPLATES = [];
11787
12530
  const readResourceTemplates = (state) => state.getResourceTemplates();
11788
12531
  function useManagedResourceTemplates(client, managedResourceTemplatesState) {
@@ -11795,8 +12538,7 @@ function useManagedResourceTemplates(client, managedResourceTemplatesState) {
11795
12538
  }, [client, managedResourceTemplatesState])
11796
12539
  };
11797
12540
  }
11798
- //#endregion
11799
- //#region ../../core/react/useManagedPrompts.ts
12541
+ // ../../core/react/useManagedPrompts.ts
11800
12542
  const NO_PROMPTS = [];
11801
12543
  const readPrompts = (state) => state.getPrompts();
11802
12544
  const readListChanged = (state) => state.getListChanged();
@@ -11820,8 +12562,7 @@ function useManagedPrompts(client, managedPromptsState) {
11820
12562
  }, [managedPromptsState])
11821
12563
  };
11822
12564
  }
11823
- //#endregion
11824
- //#region ../../core/react/useManagedSkills.ts
12565
+ // ../../core/react/useManagedSkills.ts
11825
12566
  const NO_SKILLS = [];
11826
12567
  const NO_SKILLS_PAGINATION = Object.freeze({ pageCount: 0 });
11827
12568
  const readSkills = (state) => state.getSkills();
@@ -11839,29 +12580,25 @@ function useManagedSkills(client, managedSkillsState) {
11839
12580
  }, [client, managedSkillsState])
11840
12581
  };
11841
12582
  }
11842
- //#endregion
11843
- //#region ../../core/react/useMessageLog.ts
12583
+ // ../../core/react/useMessageLog.ts
11844
12584
  const NO_MESSAGES = [];
11845
12585
  const readMessages = (state) => state.getMessages();
11846
- function useMessageLog(messageLogState) {
11847
- return { messages: useStoreSnapshot(messageLogState, "messagesChange", readMessages, NO_MESSAGES) };
12586
+ function useMessageLog(messageLogState, schedule) {
12587
+ return { messages: useStoreSnapshot(messageLogState, "messagesChange", readMessages, NO_MESSAGES, schedule) };
11848
12588
  }
11849
- //#endregion
11850
- //#region ../../core/react/useFetchRequestLog.ts
12589
+ // ../../core/react/useFetchRequestLog.ts
11851
12590
  const NO_FETCH_REQUESTS = [];
11852
12591
  const readFetchRequests = (state) => state.getFetchRequests();
11853
- function useFetchRequestLog(fetchRequestLogState) {
11854
- return { fetchRequests: useStoreSnapshot(fetchRequestLogState, "fetchRequestsChange", readFetchRequests, NO_FETCH_REQUESTS) };
12592
+ function useFetchRequestLog(fetchRequestLogState, schedule) {
12593
+ return { fetchRequests: useStoreSnapshot(fetchRequestLogState, "fetchRequestsChange", readFetchRequests, NO_FETCH_REQUESTS, schedule) };
11855
12594
  }
11856
- //#endregion
11857
- //#region ../../core/react/useStderrLog.ts
12595
+ // ../../core/react/useStderrLog.ts
11858
12596
  const NO_STDERR_LOGS = [];
11859
12597
  const readStderrLogs = (state) => state.getStderrLogs();
11860
- function useStderrLog(stderrLogState) {
11861
- return { stderrLogs: useStoreSnapshot(stderrLogState, "stderrLogsChange", readStderrLogs, NO_STDERR_LOGS) };
12598
+ function useStderrLog(stderrLogState, schedule) {
12599
+ return { stderrLogs: useStoreSnapshot(stderrLogState, "stderrLogsChange", readStderrLogs, NO_STDERR_LOGS, schedule) };
11862
12600
  }
11863
- //#endregion
11864
- //#region ../../core/react/useManagedRequestorTasks.ts
12601
+ // ../../core/react/useManagedRequestorTasks.ts
11865
12602
  const NO_TASKS = [];
11866
12603
  const readTasks = (state) => state.getTasks();
11867
12604
  function useManagedRequestorTasks(client, managedRequestorTasksState) {
@@ -11876,8 +12613,7 @@ function useManagedRequestorTasks(client, managedRequestorTasksState) {
11876
12613
  }, [managedRequestorTasksState])
11877
12614
  };
11878
12615
  }
11879
- //#endregion
11880
- //#region ../../core/react/useResourceSubscriptions.ts
12616
+ // ../../core/react/useResourceSubscriptions.ts
11881
12617
  const NO_SUBSCRIPTIONS = [];
11882
12618
  const readSubscriptions = (state) => state.getSubscriptions();
11883
12619
  const readStreamState = (state) => state.getStreamState();
@@ -11887,8 +12623,18 @@ function useResourceSubscriptions(state) {
11887
12623
  streamState: useStoreSnapshot(state, "streamStateChange", readStreamState, INACTIVE_SUBSCRIPTION_STREAM_STATE)
11888
12624
  };
11889
12625
  }
11890
- //#endregion
11891
- //#region ../../core/auth/issuerBinding.ts
12626
+ // ../../core/react/usePendingClientRequests.ts
12627
+ const NO_SAMPLES = [];
12628
+ const NO_ELICITATIONS = [];
12629
+ const readPendingSamples = (client) => client.getPendingSamples();
12630
+ const readPendingElicitations = (client) => client.getPendingElicitations();
12631
+ function usePendingClientRequests(inspectorClient) {
12632
+ return {
12633
+ pendingSamples: useStoreSnapshot(inspectorClient, "pendingSamplesChange", readPendingSamples, NO_SAMPLES),
12634
+ pendingElicitations: useStoreSnapshot(inspectorClient, "pendingElicitationsChange", readPendingElicitations, NO_ELICITATIONS)
12635
+ };
12636
+ }
12637
+ // ../../core/auth/issuerBinding.ts
11892
12638
  const MISSING_DISCOVERY_STATE_PHRASE = "discoveryState was not available";
11893
12639
  function isAuthorizationServerMismatchShape(err) {
11894
12640
  if (err === null || typeof err !== "object") return false;
@@ -11928,8 +12674,7 @@ function classifyAuthorizationServerMismatch(err) {
11928
12674
  currentIssuer: err.currentIssuer
11929
12675
  };
11930
12676
  }
11931
- //#endregion
11932
- //#region ../../core/auth/oauth-storage.ts
12677
+ // ../../core/auth/oauth-storage.ts
11933
12678
  function withIssuer(value, issuer) {
11934
12679
  return issuer === void 0 ? value : {
11935
12680
  ...value,
@@ -12206,8 +12951,7 @@ var OAuthStorageBase = class {
12206
12951
  await this.persist({ servers });
12207
12952
  }
12208
12953
  };
12209
- //#endregion
12210
- //#region ../../core/auth/store.ts
12954
+ // ../../core/auth/store.ts
12211
12955
  var OAuthMemoryStore = class {
12212
12956
  servers = {};
12213
12957
  idpSessions = {};
@@ -12270,8 +13014,7 @@ var OAuthMemoryStore = class {
12270
13014
  this.idpSessions = { ...snapshot.idpSessions ?? {} };
12271
13015
  }
12272
13016
  };
12273
- //#endregion
12274
- //#region ../../core/auth/oauth-persist.ts
13017
+ // ../../core/auth/oauth-persist.ts
12275
13018
  function mergeOAuthSections(disk, snapshot, sections) {
12276
13019
  const merged = {
12277
13020
  servers: { ...disk?.servers },
@@ -12336,8 +13079,7 @@ function parseOAuthPersistBlob(raw) {
12336
13079
  function serializeOAuthPersistBlob(snapshot) {
12337
13080
  return serializeStore(snapshot);
12338
13081
  }
12339
- //#endregion
12340
- //#region ../../core/auth/node/oauth-secrets.ts
13082
+ // ../../core/auth/node/oauth-secrets.ts
12341
13083
  const PERSIST_TOKENS_ENV = "MCP_INSPECTOR_PERSIST_TOKENS";
12342
13084
  const warnedPolicyValues = /* @__PURE__ */ new Set();
12343
13085
  function getPersistTokensPolicy(env = process.env) {
@@ -12607,8 +13349,7 @@ function snapshotHasPlaintextSecrets(snapshot) {
12607
13349
  for (const session of Object.values(snapshot.idpSessions)) if (session.idToken !== void 0 || session.refreshToken !== void 0) return true;
12608
13350
  return false;
12609
13351
  }
12610
- //#endregion
12611
- //#region ../../core/auth/node/oauth-namespace-ledger.ts
13352
+ // ../../core/auth/node/oauth-namespace-ledger.ts
12612
13353
  const namespaceLedgerPath = (stateFilePath) => `${stateFilePath}.namespaces.json`;
12613
13354
  const KEYRING_LOCATION = "keyring";
12614
13355
  const FILE_LOCATION_PREFIX = "file:";
@@ -12866,8 +13607,7 @@ async function purgeSupersededNamespaces(stateFilePath, secretStore, current, ow
12866
13607
  warnLedgerFailure("update", error);
12867
13608
  }
12868
13609
  }
12869
- //#endregion
12870
- //#region ../../core/auth/node/oauth-persist-file.ts
13610
+ // ../../core/auth/node/oauth-persist-file.ts
12871
13611
  const warnedStoreFailures = /* @__PURE__ */ new Set();
12872
13612
  function warnStoreWriteFailure(error) {
12873
13613
  const reason = error instanceof Error ? error.message : String(error);
@@ -13413,8 +14153,7 @@ function createFileOAuthPersistBackend(options) {
13413
14153
  }
13414
14154
  };
13415
14155
  }
13416
- //#endregion
13417
- //#region ../../core/auth/node/storage-node.ts
14156
+ // ../../core/auth/node/storage-node.ts
13418
14157
  const DEFAULT_STATE_PATH = getStoreFilePath(getDefaultStorageDir(), "oauth");
13419
14158
  function getStateFilePath(customPath) {
13420
14159
  if (customPath) return customPath;
@@ -13445,25 +14184,41 @@ var NodeOAuthStorage = class extends OAuthStorageBase {
13445
14184
  }), shared.coordination);
13446
14185
  }
13447
14186
  };
13448
- //#endregion
13449
- //#region ../../core/auth/node/oauth-callback-server.ts
14187
+ // ../../core/auth/node/oauth-callback-server.ts
13450
14188
  const DEFAULT_HOSTNAME = "127.0.0.1";
13451
14189
  const DEFAULT_CALLBACK_PATH = "/oauth/callback";
13452
- const SUCCESS_HTML = `<!DOCTYPE html>
13453
- <html>
13454
- <head><meta charset="utf-8"><title>OAuth complete</title></head>
13455
- <body><p>OAuth complete. You can close this window.</p></body>
13456
- </html>`;
13457
- function errorHtml(message) {
14190
+ const SUCCESS_HTML = page("OAuth complete", "OAuth complete. You can close this window.");
14191
+ const NOT_CALLBACK_HTML = page("Not the OAuth callback", "This address is not the OAuth callback the Inspector is waiting for. Sign-in has not finished; return to the Inspector to continue.");
14192
+ const STATE_MISMATCH_HTML = page("OAuth callback ignored", "This callback does not belong to the sign-in in progress and was ignored. Sign-in has not finished; the Inspector is still waiting for the authorization server.");
14193
+ const ALREADY_HANDLED_HTML = page("OAuth callback already received", "This sign-in has already received its callback. You can close this window.");
14194
+ const STOPPED_HTML = page("OAuth callback not expected", "The Inspector is no longer waiting for this sign-in. Start sign-in again from the Inspector.");
14195
+ function errorHtml(serverText) {
14196
+ return page("OAuth error", `OAuth failed. The authorization server said: ${serverText}`);
14197
+ }
14198
+ function exchangeErrorHtml(message) {
14199
+ return page("OAuth error", `OAuth failed: ${message}`);
14200
+ }
14201
+ function page(title, text) {
13458
14202
  return `<!DOCTYPE html>
13459
14203
  <html>
13460
- <head><meta charset="utf-8"><title>OAuth error</title></head>
13461
- <body><p>OAuth failed: ${escapeHtml(message)}</p></body>
14204
+ <head><meta charset="utf-8"><title>${escapeHtml(title)}</title></head>
14205
+ <body><p>${escapeHtml(text)}</p></body>
13462
14206
  </html>`;
13463
14207
  }
13464
14208
  function escapeHtml(s) {
13465
14209
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13466
14210
  }
14211
+ const ANY_STATE = Symbol("any-state");
14212
+ const STOPPED = Symbol("stopped");
14213
+ function createStopSignal() {
14214
+ let fire;
14215
+ return {
14216
+ stopped: new Promise((resolve) => {
14217
+ fire = () => resolve(STOPPED);
14218
+ }),
14219
+ fire
14220
+ };
14221
+ }
13467
14222
  var OAuthCallbackServer = class {
13468
14223
  server = null;
13469
14224
  port = 0;
@@ -13471,6 +14226,8 @@ var OAuthCallbackServer = class {
13471
14226
  handled = false;
13472
14227
  onCallback;
13473
14228
  onError;
14229
+ expectedState = Promise.resolve(ANY_STATE);
14230
+ stopSignal = createStopSignal();
13474
14231
  async start(options = {}) {
13475
14232
  const { port = 0, hostname = DEFAULT_HOSTNAME, path = DEFAULT_CALLBACK_PATH, onCallback, onError } = options;
13476
14233
  if (!path.startsWith("/")) return Promise.reject(/* @__PURE__ */ new Error("Callback path must start with '/' (absolute path)"));
@@ -13478,6 +14235,8 @@ var OAuthCallbackServer = class {
13478
14235
  this.onError = onError;
13479
14236
  this.handled = false;
13480
14237
  this.callbackPath = path;
14238
+ this.stopSignal = createStopSignal();
14239
+ this.expectedState = "expectedState" in options ? Promise.race([Promise.resolve(options.expectedState).catch(() => STOPPED), this.stopSignal.stopped]) : Promise.resolve(ANY_STATE);
13481
14240
  return new Promise((resolve, reject) => {
13482
14241
  this.server = createServer((req, res) => this.handleRequest(req, res));
13483
14242
  this.server.on("error", reject);
@@ -13501,6 +14260,7 @@ var OAuthCallbackServer = class {
13501
14260
  }
13502
14261
  async stop() {
13503
14262
  if (!this.server) return;
14263
+ this.stopSignal.fire();
13504
14264
  await new Promise((resolve) => {
13505
14265
  this.server.close(() => resolve());
13506
14266
  });
@@ -13509,11 +14269,14 @@ var OAuthCallbackServer = class {
13509
14269
  handleRequest(req, res) {
13510
14270
  const needJson = req.headers["accept"]?.includes("application/json");
13511
14271
  const send = (status, body, contentType = "text/html; charset=utf-8") => {
13512
- res.writeHead(status, { "Content-Type": contentType });
14272
+ res.writeHead(status, {
14273
+ "Content-Type": contentType,
14274
+ Connection: "close"
14275
+ });
13513
14276
  res.end(body);
13514
14277
  };
13515
14278
  if (req.method !== "GET") {
13516
- send(405, needJson ? "{\"error\":\"Method Not Allowed\"}" : SUCCESS_HTML);
14279
+ send(405, needJson ? "{\"error\":\"Method Not Allowed\"}" : NOT_CALLBACK_HTML);
13517
14280
  return;
13518
14281
  }
13519
14282
  let pathname;
@@ -13530,15 +14293,26 @@ var OAuthCallbackServer = class {
13530
14293
  search = u.search;
13531
14294
  state = u.searchParams.get("state") ?? void 0;
13532
14295
  } catch {
13533
- send(400, needJson ? "{\"error\":\"Bad Request\"}" : SUCCESS_HTML);
14296
+ send(400, needJson ? "{\"error\":\"Bad Request\"}" : NOT_CALLBACK_HTML);
13534
14297
  return;
13535
14298
  }
13536
14299
  if (pathname !== this.callbackPath) {
13537
- send(404, needJson ? "{\"error\":\"Not Found\"}" : SUCCESS_HTML);
14300
+ send(404, needJson ? "{\"error\":\"Not Found\"}" : NOT_CALLBACK_HTML);
14301
+ return;
14302
+ }
14303
+ this.expectedState.then((expected) => this.handleCallback(expected, state, search, needJson, send));
14304
+ }
14305
+ handleCallback(expected, state, search, needJson, send) {
14306
+ if (expected === STOPPED) {
14307
+ send(503, needJson ? "{\"error\":\"Not waiting for a callback\"}" : STOPPED_HTML);
14308
+ return;
14309
+ }
14310
+ if (expected !== ANY_STATE && state !== expected) {
14311
+ send(400, needJson ? "{\"error\":\"State mismatch\"}" : STATE_MISMATCH_HTML);
13538
14312
  return;
13539
14313
  }
13540
14314
  if (this.handled) {
13541
- send(409, needJson ? "{\"error\":\"Callback already handled\"}" : SUCCESS_HTML);
14315
+ send(409, needJson ? "{\"error\":\"Callback already handled\"}" : ALREADY_HANDLED_HTML);
13542
14316
  return;
13543
14317
  }
13544
14318
  const params = parseOAuthCallbackParams(search);
@@ -13556,9 +14330,10 @@ var OAuthCallbackServer = class {
13556
14330
  const msg = err instanceof Error ? err.message : String(err);
13557
14331
  this.onError?.({
13558
14332
  error: "callback_error",
13559
- error_description: msg
14333
+ error_description: msg,
14334
+ source: "callback"
13560
14335
  });
13561
- send(500, errorHtml(msg));
14336
+ send(500, exchangeErrorHtml(msg));
13562
14337
  this.stop();
13563
14338
  });
13564
14339
  else {
@@ -13571,7 +14346,8 @@ var OAuthCallbackServer = class {
13571
14346
  const msg = generateOAuthErrorDescription(params);
13572
14347
  this.onError?.({
13573
14348
  error: params.error,
13574
- error_description: params.error_description ?? void 0
14349
+ error_description: params.error_description ?? void 0,
14350
+ source: "redirect"
13575
14351
  });
13576
14352
  send(400, errorHtml(msg));
13577
14353
  }
@@ -13582,6 +14358,28 @@ function createOAuthCallbackServer() {
13582
14358
  function buildRedirectUrl(host, port, path) {
13583
14359
  return `http://${formatHostForUrl(host)}:${port}${path}`;
13584
14360
  }
14361
+ var OAuthCallbackError = class extends Error {
14362
+ name = "OAuthCallbackError";
14363
+ oauthError;
14364
+ oauthErrorDescription;
14365
+ source;
14366
+ constructor(params) {
14367
+ super(callbackErrorMessage(params));
14368
+ this.source = params.source;
14369
+ if (params.source === "redirect") {
14370
+ if (params.error) this.oauthError = params.error;
14371
+ if (params.error_description) this.oauthErrorDescription = params.error_description;
14372
+ }
14373
+ }
14374
+ };
14375
+ var OAuthCallbackTimeoutError = class extends Error {
14376
+ name = "OAuthCallbackTimeoutError";
14377
+ timeoutMs;
14378
+ constructor(timeoutMs) {
14379
+ super(`OAuth callback timed out after ${Math.round(timeoutMs / 1e3)}s`);
14380
+ this.timeoutMs = timeoutMs;
14381
+ }
14382
+ };
13585
14383
  function toRunnerOAuthError(err) {
13586
14384
  const failure = findIssuerBindingFailure(err);
13587
14385
  if (failure) {
@@ -13590,6 +14388,14 @@ function toRunnerOAuthError(err) {
13590
14388
  }
13591
14389
  return err instanceof Error ? err : new Error(String(err));
13592
14390
  }
14391
+ function stateOf(authorizationUrl) {
14392
+ return authorizationUrl.searchParams.get("state") ?? void 0;
14393
+ }
14394
+ function callbackErrorMessage(params) {
14395
+ if (params.source === "callback") return params.error_description ?? "OAuth callback failed";
14396
+ if (!params.error && !params.error_description) return "OAuth error";
14397
+ return `OAuth authorization failed. The authorization server said: ${params.error_description ? `${params.error_description} (${params.error})` : params.error}`;
14398
+ }
13593
14399
  async function runRunnerInteractiveOAuth(options) {
13594
14400
  const server = (options.createCallbackServer ?? createOAuthCallbackServer)();
13595
14401
  let flowResolve;
@@ -13619,11 +14425,16 @@ async function runRunnerInteractiveOAuth(options) {
13619
14425
  process.on("SIGTERM", onSignal);
13620
14426
  }
13621
14427
  let timeoutId;
14428
+ let resolveExpectedState;
14429
+ const expectedState = new Promise((resolve) => {
14430
+ resolveExpectedState = resolve;
14431
+ });
13622
14432
  try {
13623
14433
  const { redirectUrl } = await racingSignals(server.start({
13624
14434
  hostname: options.callbackListen.hostname,
13625
14435
  port: options.callbackListen.port,
13626
14436
  path: options.callbackListen.pathname,
14437
+ expectedState,
13627
14438
  onCallback: async (params) => {
13628
14439
  try {
13629
14440
  await options.client.completeOAuthFlow(params.code, params.iss, params.state);
@@ -13633,10 +14444,7 @@ async function runRunnerInteractiveOAuth(options) {
13633
14444
  }
13634
14445
  },
13635
14446
  onError: (params) => {
13636
- flowReject(new Error(
13637
- /* v8 ignore next -- params.error is a required non-null string, so the "OAuth error" fallback is unreachable */
13638
- params.error_description ?? params.error ?? "OAuth error"
13639
- ));
14447
+ flowReject(new OAuthCallbackError(params));
13640
14448
  }
13641
14449
  }));
13642
14450
  options.onCallbackServer?.(server);
@@ -13647,15 +14455,21 @@ async function runRunnerInteractiveOAuth(options) {
13647
14455
  if (timeoutId !== void 0) clearTimeout(timeoutId);
13648
14456
  }), new Promise((_, reject) => {
13649
14457
  timeoutId = setTimeout(() => {
13650
- reject(/* @__PURE__ */ new Error(`OAuth callback timed out after ${Math.round(timeoutMs / 1e3)}s`));
14458
+ reject(new OAuthCallbackTimeoutError(timeoutMs));
13651
14459
  }, timeoutMs);
13652
14460
  })]);
13653
14461
  waitForCallback.catch(() => {});
13654
14462
  if (options.authorizationUrl) {
14463
+ resolveExpectedState(stateOf(options.authorizationUrl));
13655
14464
  await racingSignals(options.client.beginInteractiveAuthorization(options.authorizationUrl));
13656
14465
  await waitForCallback;
13657
- } else if (await racingSignals(options.client.authenticate()) !== void 0) await waitForCallback;
13658
- else return { kind: "already_authorized" };
14466
+ } else {
14467
+ const authUrl = await racingSignals(options.client.authenticate());
14468
+ if (authUrl !== void 0) {
14469
+ resolveExpectedState(stateOf(authUrl));
14470
+ await waitForCallback;
14471
+ } else return { kind: "already_authorized" };
14472
+ }
13659
14473
  if (options.authChallenge) {
13660
14474
  if (!await racingSignals(options.client.checkAuthChallengeSatisfied(options.authChallenge, { scopeOnly: true }))) return {
13661
14475
  kind: "insufficient_scope",
@@ -13672,13 +14486,11 @@ async function runRunnerInteractiveOAuth(options) {
13672
14486
  await server.stop().catch(() => {});
13673
14487
  }
13674
14488
  }
13675
- //#endregion
13676
- //#region src/oauthMessageTone.ts
14489
+ // src/oauthMessageTone.ts
13677
14490
  function oauthMessageToneFor(message, warningText) {
13678
14491
  return message !== null && message === warningText ? "warning" : "info";
13679
14492
  }
13680
- //#endregion
13681
- //#region src/logger.ts
14493
+ // src/logger.ts
13682
14494
  let tuiLoggerInstance;
13683
14495
  function getTuiLogger() {
13684
14496
  if (!tuiLoggerInstance) {
@@ -13695,8 +14507,7 @@ function getTuiLogger() {
13695
14507
  }
13696
14508
  return tuiLoggerInstance;
13697
14509
  }
13698
- //#endregion
13699
- //#region ../../core/node/openUrl.ts
14510
+ // ../../core/node/openUrl.ts
13700
14511
  const OPEN_URL_TIMEOUT_MS = 5e3;
13701
14512
  const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
13702
14513
  function toOpenableHref(href) {
@@ -13724,8 +14535,7 @@ async function openUrl$1(url, timeoutMs = OPEN_URL_TIMEOUT_MS) {
13724
14535
  clearTimeout(timer);
13725
14536
  }
13726
14537
  }
13727
- //#endregion
13728
- //#region src/utils/openUrl.ts
14538
+ // src/utils/openUrl.ts
13729
14539
  function browserOpenFailedMessage(href) {
13730
14540
  return `Could not open a browser automatically. Open this URL manually to authorize: ${href}`;
13731
14541
  }
@@ -13737,13 +14547,11 @@ async function openUrl(url, onFailure) {
13737
14547
  onFailure?.(browserOpenFailedMessage(href));
13738
14548
  }
13739
14549
  }
13740
- //#endregion
13741
- //#region src/utils/tuiOAuth.ts
14550
+ // src/utils/tuiOAuth.ts
13742
14551
  function isStepUpConfirmation(challenge, settings) {
13743
14552
  return isStepUpConfirmation$1(challenge, { enterpriseManaged: settings?.enterpriseManaged });
13744
14553
  }
13745
- //#endregion
13746
- //#region src/components/tabsConfig.ts
14554
+ // src/components/tabsConfig.ts
13747
14555
  const tabs = [
13748
14556
  {
13749
14557
  id: "info",
@@ -13829,8 +14637,7 @@ function tabBarRows(visible, counts, width) {
13829
14637
  }
13830
14638
  return rows;
13831
14639
  }
13832
- //#endregion
13833
- //#region src/components/Tabs.tsx
14640
+ // src/components/Tabs.tsx
13834
14641
  function splitLabelAtAccelerator(label, accelerator) {
13835
14642
  const idx = label.toLowerCase().indexOf(accelerator.toLowerCase());
13836
14643
  if (idx < 0) return {
@@ -13891,8 +14698,7 @@ function Tabs({ activeTab, width, counts = {}, focused = false, showAuth = true,
13891
14698
  })
13892
14699
  });
13893
14700
  }
13894
- //#endregion
13895
- //#region node_modules/ink-scroll-view/dist/index.js
14701
+ // node_modules/ink-scroll-view/dist/index.js
13896
14702
  var MeasurableItem = ({ children, onMeasure, index, width, measureKey }) => {
13897
14703
  const ref = useRef(null);
13898
14704
  useLayoutEffect(() => {
@@ -14174,8 +14980,7 @@ var ScrollView = forwardRef(({ onScroll, onViewportSizeChange, onContentHeightCh
14174
14980
  ...boxProps
14175
14981
  });
14176
14982
  });
14177
- //#endregion
14178
- //#region src/components/InfoTab.tsx
14983
+ // src/components/InfoTab.tsx
14179
14984
  function InfoTab({ serverName, serverConfig, serverSettings = null, serverState, width, height, focused = false, roots = [], onEditRoots }) {
14180
14985
  const headerPairs = serverSettings?.headers ?? [];
14181
14986
  const headersBlock = headerPairs.length > 0 ? /* @__PURE__ */ jsx(Box, {
@@ -14414,8 +15219,7 @@ function InfoTab({ serverName, serverConfig, serverSettings = null, serverState,
14414
15219
  })] }) : null]
14415
15220
  });
14416
15221
  }
14417
- //#endregion
14418
- //#region src/components/SelectableItem.tsx
15222
+ // src/components/SelectableItem.tsx
14419
15223
  function SelectableItem({ isSelected, bold, children }) {
14420
15224
  return /* @__PURE__ */ jsxs(Box, {
14421
15225
  flexShrink: 0,
@@ -14432,8 +15236,7 @@ function SelectableItem({ isSelected, bold, children }) {
14432
15236
  })]
14433
15237
  });
14434
15238
  }
14435
- //#endregion
14436
- //#region src/utils/clipboard.ts
15239
+ // src/utils/clipboard.ts
14437
15240
  const OSC52_LARGE_PAYLOAD_BYTES = 1e5;
14438
15241
  function toCopyText(value) {
14439
15242
  if (typeof value === "string") return value;
@@ -14533,8 +15336,7 @@ function useCopyKeys(value, label) {
14533
15336
  function copyStatusColor(tone) {
14534
15337
  return tone === "success" ? "green" : tone === "warning" ? "yellow" : "red";
14535
15338
  }
14536
- //#endregion
14537
- //#region src/utils/oauthDisplay.ts
15339
+ // src/utils/oauthDisplay.ts
14538
15340
  function formatAuthProtocol(protocol) {
14539
15341
  return protocol === "ema" ? "Enterprise-managed" : "Standard";
14540
15342
  }
@@ -14556,8 +15358,7 @@ function formatScopes(state) {
14556
15358
  const scopes = (state.grantedScope ?? state.configuredScope)?.split(" ").filter(Boolean);
14557
15359
  return scopes && scopes.length > 0 ? scopes.join(", ") : void 0;
14558
15360
  }
14559
- //#endregion
14560
- //#region src/utils/errorText.ts
15361
+ // src/utils/errorText.ts
14561
15362
  function errorMessage$1(err) {
14562
15363
  return redactUrlsInText(err instanceof Error ? err.message : String(err));
14563
15364
  }
@@ -14567,8 +15368,128 @@ function redactErrorText(text) {
14567
15368
  function redactedJson(value) {
14568
15369
  return redactUrlsInText(JSON.stringify(value, null, 2) ?? String(value));
14569
15370
  }
14570
- //#endregion
14571
- //#region src/components/AuthTab.tsx
15371
+ // ../../core/auth/accessTokenClaims.ts
15372
+ const CONTROL_CHARS = /[\u0000-\u001F\u007F-\u009F]/g;
15373
+ function clean(value) {
15374
+ return value.replace(CONTROL_CHARS, "");
15375
+ }
15376
+ function stringClaim(value) {
15377
+ if (typeof value !== "string") return void 0;
15378
+ const cleaned = clean(value).trim();
15379
+ return cleaned.length > 0 ? cleaned : void 0;
15380
+ }
15381
+ function listClaim(value) {
15382
+ const strings = (Array.isArray(value) ? value : [value]).map(stringClaim).filter((s) => s !== void 0);
15383
+ return strings.length > 0 ? strings : void 0;
15384
+ }
15385
+ function scopeString(value) {
15386
+ const s = stringClaim(value);
15387
+ if (s === void 0) return void 0;
15388
+ return s.split(/\s+/).filter(Boolean);
15389
+ }
15390
+ function numericClaim(value) {
15391
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
15392
+ }
15393
+ function summarizeAccessToken(tokens) {
15394
+ const claims = decodeJwtPayload(tokens.access_token)?.payload;
15395
+ if (claims && typeof claims === "object" && !Array.isArray(claims)) return {
15396
+ format: "jwt",
15397
+ issuer: stringClaim(claims.iss),
15398
+ audience: listClaim(claims.aud),
15399
+ subject: stringClaim(claims.sub),
15400
+ clientId: stringClaim(claims.client_id) ?? stringClaim(claims.azp),
15401
+ scopes: scopeString(claims.scope) ?? (typeof claims.scp === "string" ? scopeString(claims.scp) : listClaim(claims.scp)),
15402
+ issuedAt: numericClaim(claims.iat),
15403
+ expiresAt: numericClaim(claims.exp)
15404
+ };
15405
+ return {
15406
+ format: "opaque",
15407
+ scopes: scopeString(tokens.scope),
15408
+ expiresIn: numericClaim(tokens.expires_in)
15409
+ };
15410
+ }
15411
+ function isAccessTokenSummaryExpired(summary, nowMs) {
15412
+ return summary.expiresAt !== void 0 && summary.expiresAt * 1e3 <= nowMs;
15413
+ }
15414
+ function formatDuration(seconds) {
15415
+ const s = Math.floor(Math.abs(seconds));
15416
+ if (s < 60) return `${s}s`;
15417
+ const m = Math.floor(s / 60);
15418
+ if (m < 60) return `${m}m`;
15419
+ const h = Math.floor(m / 60);
15420
+ if (h < 24) return m % 60 === 0 ? `${h}h` : `${h}h ${m % 60}m`;
15421
+ const d = Math.floor(h / 24);
15422
+ return h % 24 === 0 ? `${d}d` : `${d}d ${h % 24}h`;
15423
+ }
15424
+ function formatEpoch(epochSeconds) {
15425
+ const date = /* @__PURE__ */ new Date(epochSeconds * 1e3);
15426
+ return Number.isNaN(date.getTime()) ? String(epochSeconds) : date.toISOString();
15427
+ }
15428
+ function relativeTo(epochSeconds, nowMs) {
15429
+ const delta = epochSeconds - nowMs / 1e3;
15430
+ return delta >= 0 ? `in ${formatDuration(delta)}` : `${formatDuration(delta)} ago`;
15431
+ }
15432
+ function accessTokenDetailLines(summary, nowMs) {
15433
+ const lines = [];
15434
+ if (summary.format === "jwt") {
15435
+ lines.push({
15436
+ label: "Format",
15437
+ value: "JWT (signature not verified)"
15438
+ });
15439
+ if (summary.issuer) lines.push({
15440
+ label: "Issuer",
15441
+ value: summary.issuer
15442
+ });
15443
+ if (summary.audience) lines.push({
15444
+ label: "Audience",
15445
+ value: summary.audience.join(", ")
15446
+ });
15447
+ if (summary.subject) lines.push({
15448
+ label: "Subject",
15449
+ value: summary.subject
15450
+ });
15451
+ if (summary.clientId) lines.push({
15452
+ label: "Client",
15453
+ value: summary.clientId
15454
+ });
15455
+ if (summary.scopes) lines.push({
15456
+ label: "Scopes",
15457
+ value: summary.scopes.join(", ")
15458
+ });
15459
+ if (summary.issuedAt !== void 0) lines.push({
15460
+ label: "Issued",
15461
+ value: `${formatEpoch(summary.issuedAt)} (${relativeTo(summary.issuedAt, nowMs)})`
15462
+ });
15463
+ if (summary.expiresAt !== void 0) {
15464
+ const expired = isAccessTokenSummaryExpired(summary, nowMs);
15465
+ const rel = relativeTo(summary.expiresAt, nowMs);
15466
+ lines.push({
15467
+ label: "Expires",
15468
+ value: `${formatEpoch(summary.expiresAt)} (${expired ? `expired ${rel}` : rel})`
15469
+ });
15470
+ } else lines.push({
15471
+ label: "Expires",
15472
+ value: "no exp claim"
15473
+ });
15474
+ return lines;
15475
+ }
15476
+ lines.push({
15477
+ label: "Format",
15478
+ value: "Opaque (not a JWT)"
15479
+ });
15480
+ if (summary.scopes) lines.push({
15481
+ label: "Scopes",
15482
+ value: summary.scopes.join(", ")
15483
+ });
15484
+ lines.push({
15485
+ label: "Expires in",
15486
+ value: summary.expiresIn !== void 0 ? `${formatDuration(summary.expiresIn)} from issuance (token response expires_in)` : "not stated by the token response"
15487
+ });
15488
+ return lines;
15489
+ }
15490
+ // src/components/AuthTab.tsx
15491
+ const NO_REFUSALS = [];
15492
+ const readFetchRefusals = (client) => client.getFetchRefusals();
14572
15493
  function OAuthDetailRow({ label, value }) {
14573
15494
  return /* @__PURE__ */ jsxs(Box, {
14574
15495
  flexDirection: "row",
@@ -14654,6 +15575,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
14654
15575
  inspectorClient.removeEventListener("oauthComplete", update);
14655
15576
  };
14656
15577
  }, [inspectorClient, refreshOAuthState]);
15578
+ const fetchRefusals = useStoreSnapshot(inspectorClient, "fetchRefused", readFetchRefusals, NO_REFUSALS);
14657
15579
  const accessToken = oauthState?.tokens?.access_token;
14658
15580
  const { handleCopyKey, status: copyStatus } = useCopyKeys(accessToken, "access token");
14659
15581
  useInput((input, key) => {
@@ -14725,6 +15647,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
14725
15647
  })
14726
15648
  });
14727
15649
  const scopes = oauthState ? formatScopes(oauthState) : void 0;
15650
+ const tokenDetails = oauthState?.tokens?.access_token ? accessTokenDetailLines(summarizeAccessToken(oauthState.tokens), Date.now()) : [];
14728
15651
  return /* @__PURE__ */ jsxs(Box, {
14729
15652
  width,
14730
15653
  height,
@@ -14763,6 +15686,19 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
14763
15686
  color: oauthMessageTone === "warning" ? "yellow" : "cyan",
14764
15687
  children: oauthMessage
14765
15688
  }),
15689
+ fetchRefusals.length > 0 && /* @__PURE__ */ jsxs(Box, {
15690
+ marginTop: 1,
15691
+ flexDirection: "column",
15692
+ gap: 0,
15693
+ children: [/* @__PURE__ */ jsx(Text, {
15694
+ bold: true,
15695
+ color: "yellow",
15696
+ children: "Refused requests"
15697
+ }), fetchRefusals.map((refusal) => /* @__PURE__ */ jsx(Text, {
15698
+ color: "yellow",
15699
+ children: formatFetchRefusal(refusal)
15700
+ }, `${refusal.url} ${refusal.reason}`))]
15701
+ }),
14766
15702
  pendingStepUp ? /* @__PURE__ */ jsxs(Box, {
14767
15703
  marginTop: 1,
14768
15704
  flexDirection: "column",
@@ -14824,53 +15760,68 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
14824
15760
  flexDirection: "column",
14825
15761
  marginTop: 1,
14826
15762
  gap: 0,
14827
- children: [/* @__PURE__ */ jsx(Text, {
14828
- bold: true,
14829
- children: "OAuth Details"
14830
- }), /* @__PURE__ */ jsxs(Box, {
14831
- marginTop: 1,
14832
- flexDirection: "column",
14833
- paddingLeft: 0,
14834
- gap: 0,
14835
- children: [
14836
- /* @__PURE__ */ jsx(OAuthDetailRow, {
14837
- label: "Protocol",
14838
- value: formatAuthProtocol(oauthState.protocol)
14839
- }),
14840
- /* @__PURE__ */ jsx(OAuthDetailRow, {
14841
- label: "Status",
14842
- value: oauthState.authorized ? "Authorized" : "Not authorized"
14843
- }),
14844
- oauthState.client?.clientId && /* @__PURE__ */ jsx(OAuthDetailRow, {
14845
- label: "Client ID",
14846
- value: oauthState.client.clientId
14847
- }),
14848
- oauthState.client?.registrationKind && /* @__PURE__ */ jsx(OAuthDetailRow, {
14849
- label: "Client registration",
14850
- value: formatClientRegistrationKind(oauthState.client.registrationKind)
14851
- }),
14852
- oauthState.protocol === "ema" && oauthState.ema?.idpSession && /* @__PURE__ */ jsx(OAuthDetailRow, {
14853
- label: "IdP session",
14854
- value: formatIdpSession(oauthState.ema.idpSession)
14855
- }),
14856
- oauthState.authorizationServerMetadata?.authorization_endpoint && /* @__PURE__ */ jsx(OAuthDetailRow, {
14857
- label: "Auth URL",
14858
- value: oauthState.authorizationServerMetadata.authorization_endpoint
14859
- }),
14860
- scopes && /* @__PURE__ */ jsx(OAuthDetailRow, {
14861
- label: "Scopes",
14862
- value: scopes
14863
- }),
14864
- accessToken && /* @__PURE__ */ jsx(OAuthDetailRow, {
14865
- label: "Access token",
14866
- value: `${accessToken.slice(0, 24)}…`
14867
- }),
14868
- accessToken && copyStatus && /* @__PURE__ */ jsx(Text, {
14869
- color: copyStatusColor(copyStatus.tone),
14870
- children: copyStatus.message
14871
- })
14872
- ]
14873
- })]
15763
+ children: [
15764
+ /* @__PURE__ */ jsx(Text, {
15765
+ bold: true,
15766
+ children: "OAuth Details"
15767
+ }),
15768
+ /* @__PURE__ */ jsxs(Box, {
15769
+ marginTop: 1,
15770
+ flexDirection: "column",
15771
+ paddingLeft: 0,
15772
+ gap: 0,
15773
+ children: [
15774
+ /* @__PURE__ */ jsx(OAuthDetailRow, {
15775
+ label: "Protocol",
15776
+ value: formatAuthProtocol(oauthState.protocol)
15777
+ }),
15778
+ /* @__PURE__ */ jsx(OAuthDetailRow, {
15779
+ label: "Status",
15780
+ value: oauthState.authorized ? "Authorized" : "Not authorized"
15781
+ }),
15782
+ oauthState.client?.clientId && /* @__PURE__ */ jsx(OAuthDetailRow, {
15783
+ label: "Client ID",
15784
+ value: oauthState.client.clientId
15785
+ }),
15786
+ oauthState.client?.registrationKind && /* @__PURE__ */ jsx(OAuthDetailRow, {
15787
+ label: "Client registration",
15788
+ value: formatClientRegistrationKind(oauthState.client.registrationKind)
15789
+ }),
15790
+ oauthState.protocol === "ema" && oauthState.ema?.idpSession && /* @__PURE__ */ jsx(OAuthDetailRow, {
15791
+ label: "IdP session",
15792
+ value: formatIdpSession(oauthState.ema.idpSession)
15793
+ }),
15794
+ oauthState.authorizationServerMetadata?.authorization_endpoint && /* @__PURE__ */ jsx(OAuthDetailRow, {
15795
+ label: "Auth URL",
15796
+ value: oauthState.authorizationServerMetadata.authorization_endpoint
15797
+ }),
15798
+ scopes && /* @__PURE__ */ jsx(OAuthDetailRow, {
15799
+ label: "Scopes",
15800
+ value: scopes
15801
+ }),
15802
+ accessToken && /* @__PURE__ */ jsx(OAuthDetailRow, {
15803
+ label: "Access token",
15804
+ value: `${accessToken.slice(0, 24)}…`
15805
+ }),
15806
+ accessToken && copyStatus && /* @__PURE__ */ jsx(Text, {
15807
+ color: copyStatusColor(copyStatus.tone),
15808
+ children: copyStatus.message
15809
+ })
15810
+ ]
15811
+ }),
15812
+ tokenDetails.length > 0 && /* @__PURE__ */ jsxs(Box, {
15813
+ marginTop: 1,
15814
+ flexDirection: "column",
15815
+ gap: 0,
15816
+ children: [/* @__PURE__ */ jsx(Text, {
15817
+ bold: true,
15818
+ children: "Access Token Details"
15819
+ }), tokenDetails.map((line) => /* @__PURE__ */ jsx(OAuthDetailRow, {
15820
+ label: line.label,
15821
+ value: line.value
15822
+ }, line.label))]
15823
+ })
15824
+ ]
14874
15825
  }) : oauthStatus !== "authenticating" && /* @__PURE__ */ jsxs(Box, {
14875
15826
  marginTop: 1,
14876
15827
  flexDirection: "column",
@@ -14932,8 +15883,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
14932
15883
  ]
14933
15884
  });
14934
15885
  }
14935
- //#endregion
14936
- //#region src/hooks/useSelectableList.ts
15886
+ // src/hooks/useSelectableList.ts
14937
15887
  function clampFirstVisible(first, selected, visibleCount) {
14938
15888
  if (selected < first) return selected;
14939
15889
  if (selected >= first + visibleCount) return selected - visibleCount + 1;
@@ -14965,12 +15915,11 @@ function useSelectableList(itemCount, visibleCount, options) {
14965
15915
  ]);
14966
15916
  return {
14967
15917
  selectedIndex,
14968
- firstVisible,
15918
+ firstVisible: clampFirstVisible(firstVisible, selectedIndex, visibleCount),
14969
15919
  setSelection
14970
15920
  };
14971
15921
  }
14972
- //#endregion
14973
- //#region src/hooks/useListFilter.ts
15922
+ // src/hooks/useListFilter.ts
14974
15923
  function printable(input) {
14975
15924
  return input.replace(/[\u0000-\u001f\u007f]/g, "");
14976
15925
  }
@@ -15097,8 +16046,7 @@ function ListFilterBar({ query, editing, focused }) {
15097
16046
  function filterCount(active, shown, total) {
15098
16047
  return active ? `${shown}/${total}` : String(total);
15099
16048
  }
15100
- //#endregion
15101
- //#region src/components/ResourcesTab.tsx
16049
+ // src/components/ResourcesTab.tsx
15102
16050
  function resourceFilterFields(item) {
15103
16051
  return item.type === "resource" ? [
15104
16052
  item.data.name,
@@ -15277,7 +16225,10 @@ function ResourcesTab({ resources, resourceTemplates = [], inspectorClient, widt
15277
16225
  return /* @__PURE__ */ jsx(Box, {
15278
16226
  paddingY: 0,
15279
16227
  flexShrink: 0,
15280
- children: /* @__PURE__ */ jsxs(Text, { children: [isSelected ? "▶ " : " ", label] })
16228
+ children: /* @__PURE__ */ jsxs(Text, {
16229
+ wrap: "truncate-end",
16230
+ children: [isSelected ? "▶ " : " ", label]
16231
+ })
15281
16232
  }, key);
15282
16233
  })
15283
16234
  })
@@ -15435,8 +16386,7 @@ function ResourcesTab({ resources, resourceTemplates = [], inspectorClient, widt
15435
16386
  })]
15436
16387
  });
15437
16388
  }
15438
- //#endregion
15439
- //#region src/components/PromptsTab.tsx
16389
+ // src/components/PromptsTab.tsx
15440
16390
  function promptFilterFields(prompt) {
15441
16391
  return [prompt.name, prompt.title];
15442
16392
  }
@@ -15561,7 +16511,10 @@ function PromptsTab({ prompts, inspectorClient, width, height, focusedPane = nul
15561
16511
  return /* @__PURE__ */ jsx(Box, {
15562
16512
  paddingY: 0,
15563
16513
  flexShrink: 0,
15564
- children: /* @__PURE__ */ jsxs(Text, { children: [isSelected ? "▶ " : " ", prompt.name || `Prompt ${ordinal + 1}`] })
16514
+ children: /* @__PURE__ */ jsxs(Text, {
16515
+ wrap: "truncate-end",
16516
+ children: [isSelected ? "▶ " : " ", prompt.name || `Prompt ${ordinal + 1}`]
16517
+ })
15565
16518
  }, `${ordinal}:${prompt.name}`);
15566
16519
  })
15567
16520
  })
@@ -15649,8 +16602,7 @@ function PromptsTab({ prompts, inspectorClient, width, height, focusedPane = nul
15649
16602
  })]
15650
16603
  });
15651
16604
  }
15652
- //#endregion
15653
- //#region ../../core/extension/skills/verification.ts
16605
+ // ../../core/extension/skills/verification.ts
15654
16606
  const DEFAULT_SKILL_BUDGET_HINT = {
15655
16607
  raise: "with the server's skillCatalogMaxSkills / skillCatalogMaxBytes settings",
15656
16608
  verifyOne: "by verifying this skill alone"
@@ -15823,8 +16775,7 @@ async function verifySkills(client, entries, metadata, budgetHint = DEFAULT_SKIL
15823
16775
  }
15824
16776
  return reports;
15825
16777
  }
15826
- //#endregion
15827
- //#region src/components/SkillsTab.tsx
16778
+ // src/components/SkillsTab.tsx
15828
16779
  function skillFilterFields(skill) {
15829
16780
  return [skillDisplayName(skill), skill.frontmatter.name];
15830
16781
  }
@@ -16279,8 +17230,7 @@ function SkillsTab({ skills, pageCount, loadError = null, inspectorClient, width
16279
17230
  })]
16280
17231
  });
16281
17232
  }
16282
- //#endregion
16283
- //#region ../../core/json/schemaLint.ts
17233
+ // ../../core/json/schemaLint.ts
16284
17234
  const BOOLEAN_VALUED_KEYWORDS = /* @__PURE__ */ new Set([
16285
17235
  "additionalProperties",
16286
17236
  "unevaluatedProperties",
@@ -16474,8 +17424,7 @@ function lintToolSchemas(tool) {
16474
17424
  if (tool.outputSchema !== void 0) lintSchema(tool.outputSchema, "outputSchema", findings);
16475
17425
  return findings;
16476
17426
  }
16477
- //#endregion
16478
- //#region src/components/ToolsTab.tsx
17427
+ // src/components/ToolsTab.tsx
16479
17428
  const SEVERITY_MARKER = {
16480
17429
  error: {
16481
17430
  glyph: "!",
@@ -16603,17 +17552,19 @@ function ToolsTab({ tools, isConnected, width, height, focusedPane = null, onTes
16603
17552
  const isSelected = index === selectedIndex;
16604
17553
  const marker = schemaMarker(findingsByTool.get(tool));
16605
17554
  const ordinal = filter.indices[index];
16606
- return /* @__PURE__ */ jsx(Box, {
17555
+ return /* @__PURE__ */ jsxs(Box, {
16607
17556
  paddingY: 0,
16608
17557
  flexShrink: 0,
16609
- children: /* @__PURE__ */ jsxs(Text, { children: [
16610
- isSelected ? "▶ " : " ",
16611
- tool.name || `Tool ${ordinal + 1}`,
16612
- marker && /* @__PURE__ */ jsxs(Text, {
17558
+ children: [/* @__PURE__ */ jsxs(Text, {
17559
+ wrap: "truncate-end",
17560
+ children: [isSelected ? "▶ " : " ", tool.name || `Tool ${ordinal + 1}`]
17561
+ }), marker && /* @__PURE__ */ jsx(Box, {
17562
+ flexShrink: 0,
17563
+ children: /* @__PURE__ */ jsxs(Text, {
16613
17564
  color: marker.color,
16614
17565
  children: [" ", marker.glyph]
16615
17566
  })
16616
- ] })
17567
+ })]
16617
17568
  }, `${ordinal}:${tool.name}`);
16618
17569
  })
16619
17570
  })
@@ -16628,18 +17579,23 @@ function ToolsTab({ tools, isConnected, width, height, focusedPane = null, onTes
16628
17579
  /* @__PURE__ */ jsxs(Box, {
16629
17580
  flexShrink: 0,
16630
17581
  flexDirection: "row",
17582
+ flexWrap: "wrap",
16631
17583
  justifyContent: "space-between",
17584
+ columnGap: 1,
16632
17585
  paddingTop: 1,
16633
17586
  children: [/* @__PURE__ */ jsx(Text, {
16634
17587
  bold: true,
16635
17588
  backgroundColor: focusedPane === "details" ? "yellow" : void 0,
16636
17589
  ...focusedPane === "details" ? {} : { color: "cyan" },
16637
17590
  children: selectedTool.name
16638
- }), isConnected && /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx(Text, {
16639
- color: "cyan",
16640
- bold: true,
16641
- children: "[Enter to Test]"
16642
- }) })]
17591
+ }), isConnected && /* @__PURE__ */ jsx(Box, {
17592
+ flexShrink: 0,
17593
+ children: /* @__PURE__ */ jsx(Text, {
17594
+ color: "cyan",
17595
+ bold: true,
17596
+ children: "[Enter to Test]"
17597
+ })
17598
+ })]
16643
17599
  }),
16644
17600
  /* @__PURE__ */ jsxs(ScrollView, {
16645
17601
  ref: scrollViewRef,
@@ -16732,8 +17688,7 @@ function ToolsTab({ tools, isConnected, width, height, focusedPane = null, onTes
16732
17688
  })]
16733
17689
  });
16734
17690
  }
16735
- //#endregion
16736
- //#region src/components/NotificationsTab.tsx
17691
+ // src/components/NotificationsTab.tsx
16737
17692
  function NotificationsTab({ stderrLogs, width, height, onCountChange, focused = false }) {
16738
17693
  const scrollViewRef = useRef(null);
16739
17694
  const onCountChangeRef = useRef(onCountChange);
@@ -16821,8 +17776,7 @@ function layoutBody(body, maxLines = 500, maxLineChars = MAX_BODY_LINE_CHARS) {
16821
17776
  totalLines: all.length
16822
17777
  };
16823
17778
  }
16824
- //#endregion
16825
- //#region src/components/BodyLines.tsx
17779
+ // src/components/BodyLines.tsx
16826
17780
  function BodyLines({ body, keyPrefix }) {
16827
17781
  const { lines, hiddenLines, totalLines } = layoutBody(body);
16828
17782
  return /* @__PURE__ */ jsxs(Fragment, { children: [lines.map((line, idx) => /* @__PURE__ */ jsx(Box, {
@@ -16849,8 +17803,7 @@ function BodyLines({ body, keyPrefix }) {
16849
17803
  })
16850
17804
  })] });
16851
17805
  }
16852
- //#endregion
16853
- //#region src/components/HistoryTab.tsx
17806
+ // src/components/HistoryTab.tsx
16854
17807
  function HistoryTab({ messages, width, height, onCountChange, focusedPane = null, onViewDetails, modalOpen = false }) {
16855
17808
  const visibleCount = Math.max(1, height - 7);
16856
17809
  const { selectedIndex, firstVisible, setSelection } = useSelectableList(messages.length, visibleCount);
@@ -17058,8 +18011,7 @@ function HistoryTab({ messages, width, height, onCountChange, focusedPane = null
17058
18011
  })]
17059
18012
  });
17060
18013
  }
17061
- //#endregion
17062
- //#region src/components/RequestsTab.tsx
18014
+ // src/components/RequestsTab.tsx
17063
18015
  function RequestsTab({ requests, width, height, onCountChange, focusedPane = null, onViewDetails, modalOpen = false }) {
17064
18016
  const visibleCount = Math.max(1, height - 7);
17065
18017
  const { selectedIndex, firstVisible, setSelection } = useSelectableList(requests.length, visibleCount);
@@ -17355,8 +18307,7 @@ function RequestsTab({ requests, width, height, onCountChange, focusedPane = nul
17355
18307
  })]
17356
18308
  });
17357
18309
  }
17358
- //#endregion
17359
- //#region node_modules/ink-form/lib/FormHeader.js
18310
+ // node_modules/ink-form/lib/FormHeader.js
17360
18311
  const FormHeader = (props) => {
17361
18312
  const sections = props.form.sections;
17362
18313
  useInput((input, key) => {
@@ -17375,8 +18326,7 @@ const FormHeader = (props) => {
17375
18326
  underline: props.currentTab === id
17376
18327
  }, section.title), React$1.createElement(Text, null, " "))) : React$1.createElement(Box, null, React$1.createElement(Text, null, "Editing ", props.editingField)))));
17377
18328
  };
17378
- //#endregion
17379
- //#region node_modules/chalk/source/vendor/ansi-styles/index.js
18329
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
17380
18330
  const ANSI_BACKGROUND_OFFSET = 10;
17381
18331
  const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
17382
18332
  const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
@@ -17539,8 +18489,7 @@ function assembleStyles() {
17539
18489
  return styles$1;
17540
18490
  }
17541
18491
  const ansiStyles = assembleStyles();
17542
- //#endregion
17543
- //#region node_modules/chalk/source/vendor/supports-color/index.js
18492
+ // node_modules/chalk/source/vendor/supports-color/index.js
17544
18493
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
17545
18494
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
17546
18495
  const position = argv.indexOf(prefix + flag);
@@ -17627,8 +18576,7 @@ const supportsColor = {
17627
18576
  stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
17628
18577
  stderr: createSupportsColor({ isTTY: tty.isatty(2) })
17629
18578
  };
17630
- //#endregion
17631
- //#region node_modules/chalk/source/utilities.js
18579
+ // node_modules/chalk/source/utilities.js
17632
18580
  function stringReplaceAll(string, substring, replacer) {
17633
18581
  let index = string.indexOf(substring);
17634
18582
  if (index === -1) return string;
@@ -17655,8 +18603,7 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
17655
18603
  returnValue += string.slice(endIndex);
17656
18604
  return returnValue;
17657
18605
  }
17658
- //#endregion
17659
- //#region node_modules/chalk/source/index.js
18606
+ // node_modules/chalk/source/index.js
17660
18607
  const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
17661
18608
  const GENERATOR = Symbol("GENERATOR");
17662
18609
  const STYLER = Symbol("STYLER");
@@ -17777,8 +18724,7 @@ const applyStyle = (self, string) => {
17777
18724
  Object.defineProperties(createChalk.prototype, styles);
17778
18725
  const chalk = createChalk();
17779
18726
  createChalk({ level: stderrColor ? stderrColor.level : 0 });
17780
- //#endregion
17781
- //#region node_modules/ink-text-input/build/index.js
18727
+ // node_modules/ink-text-input/build/index.js
17782
18728
  function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
17783
18729
  const [state, setState] = useState({
17784
18730
  cursorOffset: (originalValue || "").length,
@@ -17847,8 +18793,7 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
17847
18793
  }, { isActive: focus });
17848
18794
  return React.createElement(Text, null, placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue);
17849
18795
  }
17850
- //#endregion
17851
- //#region node_modules/ink-form/lib/NumberFieldRenderer.js
18796
+ // node_modules/ink-form/lib/NumberFieldRenderer.js
17852
18797
  const FLOAT_REGEX = /^-?((\d+)|(\d*\.\d+))$/;
17853
18798
  const INTEGER_REGEX = /^-?\d+$/;
17854
18799
  const NumberFieldRenderer = (props) => {
@@ -17897,8 +18842,7 @@ const NumberFieldRenderer = (props) => {
17897
18842
  onSubmit: () => props.onSetEditingField(void 0)
17898
18843
  })), React.createElement(Box, null, React.createElement(Text, { dimColor: true }, "Press UP/DOWN to increase or decrease the value.")));
17899
18844
  };
17900
- //#endregion
17901
- //#region node_modules/ink-form/lib/managers/FloatFormFieldManager.js
18845
+ // node_modules/ink-form/lib/managers/FloatFormFieldManager.js
17902
18846
  var FloatFormFieldManager = class {
17903
18847
  type = "float";
17904
18848
  renderField = (props) => React.createElement(NumberFieldRenderer, {
@@ -17907,8 +18851,7 @@ var FloatFormFieldManager = class {
17907
18851
  });
17908
18852
  renderValue = (props) => React.createElement(React.Fragment, null, props.value);
17909
18853
  };
17910
- //#endregion
17911
- //#region node_modules/ink-form/lib/managers/IntegerFormFieldManager.js
18854
+ // node_modules/ink-form/lib/managers/IntegerFormFieldManager.js
17912
18855
  var IntegerFormFieldManager = class {
17913
18856
  type = "integer";
17914
18857
  renderField = (props) => React.createElement(NumberFieldRenderer, {
@@ -17917,16 +18860,14 @@ var IntegerFormFieldManager = class {
17917
18860
  });
17918
18861
  renderValue = (props) => React.createElement(React.Fragment, null, props.value);
17919
18862
  };
17920
- //#endregion
17921
- //#region node_modules/is-unicode-supported/index.js
18863
+ // node_modules/is-unicode-supported/index.js
17922
18864
  function isUnicodeSupported() {
17923
18865
  const { env } = process$1;
17924
18866
  const { TERM, TERM_PROGRAM } = env;
17925
18867
  if (process$1.platform !== "win32") return TERM !== "linux";
17926
18868
  return Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
17927
18869
  }
17928
- //#endregion
17929
- //#region node_modules/figures/index.js
18870
+ // node_modules/figures/index.js
17930
18871
  const common = {
17931
18872
  circleQuestionMark: "(?)",
17932
18873
  questionMarkPrefix: "(?)",
@@ -18205,18 +19146,15 @@ const fallbackSymbols = {
18205
19146
  };
18206
19147
  const figures = isUnicodeSupported() ? mainSymbols : fallbackSymbols;
18207
19148
  Object.entries(specialMainSymbols);
18208
- //#endregion
18209
- //#region node_modules/ink-select-input/build/Indicator.js
19149
+ // node_modules/ink-select-input/build/Indicator.js
18210
19150
  function Indicator({ isSelected = false }) {
18211
19151
  return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures.pointer) : React.createElement(Text, null, " "));
18212
19152
  }
18213
- //#endregion
18214
- //#region node_modules/ink-select-input/build/Item.js
19153
+ // node_modules/ink-select-input/build/Item.js
18215
19154
  function Item({ isSelected = false, label }) {
18216
19155
  return React$1.createElement(Text, { color: isSelected ? "blue" : void 0 }, label);
18217
19156
  }
18218
- //#endregion
18219
- //#region node_modules/to-rotated/index.js
19157
+ // node_modules/to-rotated/index.js
18220
19158
  function toRotated(array, steps) {
18221
19159
  if (!Array.isArray(array)) throw new TypeError(`Expected an array, got \`${typeof array}\`.`);
18222
19160
  if (!Number.isSafeInteger(steps)) throw new TypeError(`The \`steps\` parameter must be an integer, got ${steps}.`);
@@ -18226,8 +19164,7 @@ function toRotated(array, steps) {
18226
19164
  if (normalizedSteps === 0) return [...array];
18227
19165
  return [...array.slice(-normalizedSteps), ...array.slice(0, -normalizedSteps)];
18228
19166
  }
18229
- //#endregion
18230
- //#region node_modules/ink-select-input/build/SelectInput.js
19167
+ // node_modules/ink-select-input/build/SelectInput.js
18231
19168
  function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator, itemComponent = Item, limit: customLimit, onSelect, onHighlight }) {
18232
19169
  const hasLimit = typeof customLimit === "number" && items.length > customLimit;
18233
19170
  const limit = hasLimit ? Math.min(customLimit, items.length) : items.length;
@@ -18294,8 +19231,7 @@ function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicator
18294
19231
  }));
18295
19232
  }));
18296
19233
  }
18297
- //#endregion
18298
- //#region node_modules/ink-form/lib/managers/SelectFormFieldManager.js
19234
+ // node_modules/ink-form/lib/managers/SelectFormFieldManager.js
18299
19235
  var SelectFormFieldManager = class {
18300
19236
  type = "select";
18301
19237
  renderField = (props) => React.createElement(Box, {
@@ -18311,8 +19247,7 @@ var SelectFormFieldManager = class {
18311
19247
  }));
18312
19248
  renderValue = (props) => React.createElement(React.Fragment, null, props.field.options.find((option) => option.value === props.value)?.label ?? props.value ?? "No value");
18313
19249
  };
18314
- //#endregion
18315
- //#region node_modules/ink-form/lib/managers/StringFormFieldManager.js
19250
+ // node_modules/ink-form/lib/managers/StringFormFieldManager.js
18316
19251
  var StringFormFieldManager = class {
18317
19252
  type = "string";
18318
19253
  renderField = (props) => React.createElement(Box, {
@@ -18331,8 +19266,7 @@ var StringFormFieldManager = class {
18331
19266
  }));
18332
19267
  renderValue = (props) => React.createElement(Transform, { transform: props.value !== void 0 && props.field.mask ? (text) => text.split("").map((char) => "*").join("") : (text) => text }, props.value);
18333
19268
  };
18334
- //#endregion
18335
- //#region node_modules/ink-form/lib/managers/BooleanFormFieldManager.js
19269
+ // node_modules/ink-form/lib/managers/BooleanFormFieldManager.js
18336
19270
  var BooleanFormFieldManager = class {
18337
19271
  type = "boolean";
18338
19272
  renderField = (props) => {
@@ -18348,8 +19282,7 @@ var BooleanFormFieldManager = class {
18348
19282
  };
18349
19283
  renderValue = (props) => React.createElement(Text, null, props.value === void 0 ? "[Not set]" : props.value ? "[True]" : "[False]");
18350
19284
  };
18351
- //#endregion
18352
- //#region node_modules/ink-form/lib/managers/managers.js
19285
+ // node_modules/ink-form/lib/managers/managers.js
18353
19286
  const managers = [
18354
19287
  new FloatFormFieldManager(),
18355
19288
  new IntegerFormFieldManager(),
@@ -18360,8 +19293,7 @@ const managers = [
18360
19293
  const getManager = (formFieldType, customManagers = []) => {
18361
19294
  return [...managers, ...customManagers].find((manager) => manager.type === formFieldType);
18362
19295
  };
18363
- //#endregion
18364
- //#region node_modules/ink-form/lib/DescriptionRenderer.js
19296
+ // node_modules/ink-form/lib/DescriptionRenderer.js
18365
19297
  const DescriptionRenderer = (props) => {
18366
19298
  if (!props.description) return null;
18367
19299
  else if (props.description.type) return props.description;
@@ -18372,8 +19304,7 @@ const DescriptionRenderer = (props) => {
18372
19304
  }, React.createElement(Text, null, line))));
18373
19305
  else return React.createElement(Text, null, props.description);
18374
19306
  };
18375
- //#endregion
18376
- //#region node_modules/ink-form/lib/FormFieldRenderer.js
19307
+ // node_modules/ink-form/lib/FormFieldRenderer.js
18377
19308
  const FormFieldRenderer = (props) => {
18378
19309
  const manager = getManager(props.field.type, props.customManagers);
18379
19310
  const [error, setError] = useState();
@@ -18439,13 +19370,11 @@ const FormFieldRenderer = (props) => {
18439
19370
  }, React.createElement(Box, null, React.createElement(Text, null, props.field.label ?? props.field.name), props.field.required && React.createElement(Text, { color: "red" }, "*"), React.createElement(Text, null, ": ")), React.createElement(Box, null, component), props.field.description && React.createElement(Box, null, React.createElement(Text, { dimColor: true }, React.createElement(DescriptionRenderer, { description: props.field.description }))), error && React.createElement(Box, null, React.createElement(Text, { color: "red" }, "Error: ", error)), React.createElement(Box, { marginTop: 2 }, React.createElement(Text, { dimColor: true }, error ? React.createElement(React.Fragment, null, "Press ESC to cancel.") : React.createElement(React.Fragment, null, "Press ", manager?.needCtrlToReturnSave ? "CTRL+Enter" : "Enter", " to complete field, or ESC to cancel."))));
18440
19371
  }
18441
19372
  };
18442
- //#endregion
18443
- //#region node_modules/ink-form/lib/canSubmit.js
19373
+ // node_modules/ink-form/lib/canSubmit.js
18444
19374
  const canSubmit = (form, value) => {
18445
19375
  return form.sections.map((section) => section.fields).reduce((fields1, fields2) => [...fields1, ...fields2], []).map((field) => !field.required || value[field.name] !== void 0 && value[field.name] !== "").reduce((field1, field2) => field1 && field2, true);
18446
19376
  };
18447
- //#endregion
18448
- //#region node_modules/ink-form/lib/SubmitButton.js
19377
+ // node_modules/ink-form/lib/SubmitButton.js
18449
19378
  const SubmitButton = (props) => {
18450
19379
  const { isFocused } = useFocus({ isActive: props.canSubmit });
18451
19380
  useInput((input, key) => {
@@ -18464,8 +19393,7 @@ const SubmitButton = (props) => {
18464
19393
  underline: isFocused
18465
19394
  }, props.canSubmit ? "Submit form" : "Cannot submit form yet")));
18466
19395
  };
18467
- //#endregion
18468
- //#region node_modules/ink-form/lib/Form.js
19396
+ // node_modules/ink-form/lib/Form.js
18469
19397
  const Form = (props) => {
18470
19398
  const isControlled = props.value !== void 0;
18471
19399
  const [currentTab, setCurrentTab] = useState(0);
@@ -18525,8 +19453,29 @@ const Form = (props) => {
18525
19453
  onSubmit: () => props.onSubmit?.(value)
18526
19454
  })));
18527
19455
  };
18528
- //#endregion
18529
- //#region src/utils/schemaToForm.ts
19456
+ // src/utils/multiSelectField.ts
19457
+ const MULTISELECT_FIELD_TYPE = "multiselect";
19458
+ function toggleChoice(selected, value, options) {
19459
+ const next = new Set(selected);
19460
+ if (next.has(value)) next.delete(value);
19461
+ else next.add(value);
19462
+ return options.map((option) => option.value).filter((each) => next.has(each));
19463
+ }
19464
+ function boundsHint(minItems, maxItems) {
19465
+ if (minItems !== void 0 && maxItems !== void 0) return minItems === maxItems ? `Choose exactly ${minItems}` : `Choose ${minItems} to ${maxItems}`;
19466
+ if (minItems !== void 0) return `Choose at least ${minItems}`;
19467
+ if (maxItems !== void 0) return `Choose at most ${maxItems}`;
19468
+ }
19469
+ function selectionLabel(options, value) {
19470
+ if (value === void 0) return "No value";
19471
+ if (value.length === 0) return "None selected";
19472
+ return value.map((each) => options.find((option) => option.value === each)?.label ?? each).join(", ");
19473
+ }
19474
+ function windowStart(cursor, count, limit) {
19475
+ if (count <= limit) return 0;
19476
+ return Math.min(Math.max(0, cursor - Math.floor(limit / 2)), count - limit);
19477
+ }
19478
+ // src/utils/schemaToForm.ts
18530
19479
  function toSelectOptions(values, names) {
18531
19480
  const useNames = names !== void 0 && names.length === values.length;
18532
19481
  return values.map((val, index) => ({
@@ -18534,6 +19483,19 @@ function toSelectOptions(values, names) {
18534
19483
  value: String(val)
18535
19484
  }));
18536
19485
  }
19486
+ function choiceOptions(members, names) {
19487
+ return toSelectOptions(members, names).map((option, index) => ({
19488
+ label: option.label,
19489
+ value: String(index)
19490
+ }));
19491
+ }
19492
+ function choiceIds(members, chosen) {
19493
+ return chosen.map((value) => members.findIndex((member) => sameJsonValue(member, value))).filter((index) => index >= 0).map(String);
19494
+ }
19495
+ function memberForChoiceId(members, id) {
19496
+ const index = typeof id === "string" && /^\d+$/.test(id) ? Number(id) : -1;
19497
+ return index >= 0 && index < members.length ? members[index] : id;
19498
+ }
18537
19499
  function generatedNames(base, branches) {
18538
19500
  const declared = [...Object.keys(base.properties ?? {}), ...branches.flatMap((branch) => branch.declaredFields)];
18539
19501
  let variant = "__variant";
@@ -18570,6 +19532,12 @@ function constOf(schema) {
18570
19532
  if (typeof schema !== "object" || schema === null) return void 0;
18571
19533
  return schema.const;
18572
19534
  }
19535
+ function isChoiceArray(property) {
19536
+ return property.type === "array" && Array.isArray(property.items?.enum);
19537
+ }
19538
+ function declarationOf(prop) {
19539
+ return normalizeNullableUnion(typeof prop === "object" && prop !== null ? prop : {});
19540
+ }
18573
19541
  function schemaToForm(schema, toolName) {
18574
19542
  const title = `Test Tool: ${toolName}`;
18575
19543
  if (!schema) return {
@@ -18625,7 +19593,7 @@ function schemaToForm(schema, toolName) {
18625
19593
  }
18626
19594
  function decodeFormValues(schema, values) {
18627
19595
  const { base, branches } = resolveRootUnion(schema ?? {});
18628
- if (branches.length === 0) return applyConstants(base.properties ?? {}, values, requiredOf(base));
19596
+ if (branches.length === 0) return restoreChoices(base.properties ?? {}, applyConstants(base.properties ?? {}, values, requiredOf(base)), requiredOf(base));
18629
19597
  const { variant, prefix } = generatedNames(base, branches);
18630
19598
  const branchIndex = selectedBranchIndex(base, branches, values);
18631
19599
  const branch = branches[branchIndex];
@@ -18635,7 +19603,9 @@ function decodeFormValues(schema, values) {
18635
19603
  });
18636
19604
  const decoded = Object.fromEntries([...Object.entries(values).filter(([name]) => !generated.has(name)), ...branchFields(base, branches, branchIndex).map((name) => [name, values[branchFieldName(prefix, branchIndex, name)]]).filter(([, value]) => value !== void 0)]);
18637
19605
  /* v8 ignore next -- an offerable branch always carries properties */
18638
- return applyConstants(branch.schema.properties ?? {}, decoded, requiredOf(branch.schema));
19606
+ const properties = branch.schema.properties ?? {};
19607
+ const required = requiredOf(branch.schema);
19608
+ return restoreChoices(properties, applyConstants(properties, decoded, required), required);
18639
19609
  }
18640
19610
  function selectedBranchIndex(base, branches, values) {
18641
19611
  const { variant } = generatedNames(base, branches);
@@ -18647,12 +19617,24 @@ function applyConstants(properties, values, required) {
18647
19617
  if (pinned.length === 0) return values;
18648
19618
  return Object.fromEntries([...Object.entries(values), ...pinned.map(([name, schema]) => [name, constOf(schema)])]);
18649
19619
  }
19620
+ function restoreChoices(properties, values, required) {
19621
+ const choiceFields = Object.entries(properties).map(([name, prop]) => [name, declarationOf(prop)]).filter(([name, property]) => isChoiceArray(property) && property.const === void 0 && Object.hasOwn(values, name) && Array.isArray(values[name]));
19622
+ if (choiceFields.length === 0) return values;
19623
+ const restored = new Map(choiceFields.map(([name, property]) => {
19624
+ const chosen = values[name];
19625
+ if (chosen.length === 0 && !required.includes(name)) return [name, void 0];
19626
+ /* v8 ignore next -- `isChoiceArray` guarantees `items.enum` above */
19627
+ const members = property.items?.enum ?? [];
19628
+ return [name, chosen.map((each) => memberForChoiceId(members, each))];
19629
+ }));
19630
+ return Object.fromEntries(Object.entries(values).map(([name, value]) => restored.has(name) ? [name, restored.get(name)] : [name, value]).filter(([, value]) => value !== void 0));
19631
+ }
18650
19632
  function buildFields(schema, { optional = false } = {}) {
18651
19633
  const fields = [];
18652
19634
  const properties = schema.properties || {};
18653
19635
  const required = Array.isArray(schema.required) ? schema.required : [];
18654
19636
  for (const [key, prop] of Object.entries(properties)) {
18655
- const property = normalizeNullableUnion(typeof prop === "object" && prop !== null ? prop : {});
19637
+ const property = declarationOf(prop);
18656
19638
  const baseField = {
18657
19639
  name: key,
18658
19640
  label: property.title || key,
@@ -18673,12 +19655,18 @@ function buildFields(schema, { optional = false } = {}) {
18673
19655
  });
18674
19656
  continue;
18675
19657
  }
18676
- if (property.type === "array" && property.items?.enum) field = {
18677
- type: "select",
18678
- ...baseField,
18679
- options: toSelectOptions(property.items.enum, property.items.enumNames)
18680
- };
18681
- else if (isStringEnum(property.enum)) field = {
19658
+ if (isChoiceArray(property)) {
19659
+ const multi = {
19660
+ type: MULTISELECT_FIELD_TYPE,
19661
+ ...baseField,
19662
+ options: choiceOptions(property.items.enum, property.items.enumNames),
19663
+ ...typeof property.minItems === "number" && { minItems: property.minItems },
19664
+ ...typeof property.maxItems === "number" && { maxItems: property.maxItems },
19665
+ ...Array.isArray(property.default) && { initialValue: choiceIds(property.items.enum, property.default) }
19666
+ };
19667
+ fields.push(multi);
19668
+ continue;
19669
+ } else if (isStringEnum(property.enum)) field = {
18682
19670
  type: "select",
18683
19671
  ...baseField,
18684
19672
  /* v8 ignore next -- guarded by `isStringEnum(property.enum)` above */
@@ -18738,8 +19726,95 @@ function missingRequiredFields(schema, decoded, rawValues = {}) {
18738
19726
  return value === void 0;
18739
19727
  });
18740
19728
  }
18741
- //#endregion
18742
- //#region ../../core/mcp/resultFile.ts
19729
+ function selectionCountErrors(schema, decoded, rawValues = {}) {
19730
+ const { base, branches } = resolveRootUnion(schema ?? {});
19731
+ /* v8 ignore next -- an offerable branch always carries properties */
19732
+ const properties = (branches.length === 0 ? base : branches[selectedBranchIndex(base, branches, rawValues)].schema).properties ?? {};
19733
+ return Object.entries(properties).flatMap(([name, prop]) => {
19734
+ const value = Object.hasOwn(decoded, name) ? decoded[name] : void 0;
19735
+ if (!Array.isArray(value)) return [];
19736
+ const { minItems, maxItems } = declarationOf(prop);
19737
+ if (typeof minItems === "number" && value.length < minItems) return [`${name}: choose at least ${minItems}`];
19738
+ if (typeof maxItems === "number" && value.length > maxItems) return [`${name}: choose at most ${maxItems}`];
19739
+ return [];
19740
+ });
19741
+ }
19742
+ function MultiSelectInput({ field, value, onChange }) {
19743
+ const [cursor, setCursor] = useState(0);
19744
+ const selected = value ?? [];
19745
+ const count = field.options.length;
19746
+ useInput((input, key) => {
19747
+ if (key.upArrow) setCursor((current) => Math.max(0, current - 1));
19748
+ else if (key.downArrow) setCursor((current) => Math.min(count - 1, current + 1));
19749
+ else if (input === " ") {
19750
+ const option = field.options[cursor];
19751
+ if (option) onChange(toggleChoice(selected, option.value, field.options));
19752
+ }
19753
+ });
19754
+ const start = windowStart(cursor, count, 8);
19755
+ const hint = boundsHint(field.minItems, field.maxItems);
19756
+ return /* @__PURE__ */ jsxs(Box, {
19757
+ width: "100%",
19758
+ borderStyle: "round",
19759
+ flexDirection: "column",
19760
+ children: [
19761
+ field.options.slice(start, start + 8).map((option, offset) => {
19762
+ const active = start + offset === cursor;
19763
+ const checked = selected.includes(option.value);
19764
+ return /* @__PURE__ */ jsxs(Text, {
19765
+ color: active ? "blue" : void 0,
19766
+ children: [
19767
+ active ? "❯ " : " ",
19768
+ checked ? "[x] " : "[ ] ",
19769
+ option.label ?? option.value
19770
+ ]
19771
+ }, option.value);
19772
+ }),
19773
+ count > 8 && /* @__PURE__ */ jsxs(Text, {
19774
+ dimColor: true,
19775
+ children: [
19776
+ start + 1,
19777
+ "-",
19778
+ start + 8,
19779
+ " of ",
19780
+ count
19781
+ ]
19782
+ }),
19783
+ /* @__PURE__ */ jsxs(Text, {
19784
+ dimColor: true,
19785
+ children: [
19786
+ "Up/Down to move, Space to toggle (",
19787
+ selected.length,
19788
+ " selected)",
19789
+ hint ? `. ${hint}` : ""
19790
+ ]
19791
+ })
19792
+ ]
19793
+ });
19794
+ }
19795
+ function isMultiSelectField(field) {
19796
+ return field.type === MULTISELECT_FIELD_TYPE;
19797
+ }
19798
+ function asSelection(value) {
19799
+ return Array.isArray(value) ? value.filter((each) => typeof each === "string") : void 0;
19800
+ }
19801
+ const FORM_FIELD_MANAGERS = [{
19802
+ type: MULTISELECT_FIELD_TYPE,
19803
+ renderField: (props) => isMultiSelectField(props.field) ? /* @__PURE__ */ jsx(MultiSelectInput, {
19804
+ field: props.field,
19805
+ value: asSelection(props.value),
19806
+ onChange: props.onChange
19807
+ }) : null,
19808
+ renderValue: (props) => isMultiSelectField(props.field) ? /* @__PURE__ */ jsx(Fragment, { children: selectionLabel(props.field.options, asSelection(props.value)) }) : null
19809
+ }];
19810
+ // src/utils/formHeader.ts
19811
+ function untitledForm(form) {
19812
+ return {
19813
+ ...form,
19814
+ title: void 0
19815
+ };
19816
+ }
19817
+ // ../../core/mcp/resultFile.ts
18743
19818
  var RawResultUnavailableError = class extends Error {
18744
19819
  method;
18745
19820
  binaryCount;
@@ -18785,8 +19860,7 @@ function renderResultForFile(result, method, format) {
18785
19860
  function renderedByteLength(data) {
18786
19861
  return typeof data === "string" ? new TextEncoder().encode(data).length : data.length;
18787
19862
  }
18788
- //#endregion
18789
- //#region src/utils/saveResult.ts
19863
+ // src/utils/saveResult.ts
18790
19864
  function fileSafe(name) {
18791
19865
  const safe = name.replace(/[^A-Za-z0-9._-]/g, "_");
18792
19866
  return safe === "" ? "tool" : safe;
@@ -18830,8 +19904,7 @@ async function writeResult(result, path, format, cwd) {
18830
19904
  function errorMessage(err) {
18831
19905
  return err instanceof Error ? err.message : String(err);
18832
19906
  }
18833
- //#endregion
18834
- //#region src/components/SaveResultBar.tsx
19907
+ // src/components/SaveResultBar.tsx
18835
19908
  function SaveResultBar({ prompt, status }) {
18836
19909
  if (prompt) return /* @__PURE__ */ jsxs(Box, {
18837
19910
  flexShrink: 0,
@@ -18866,9 +19939,8 @@ function SaveResultBar({ prompt, status }) {
18866
19939
  });
18867
19940
  return null;
18868
19941
  }
18869
- //#endregion
18870
- //#region src/components/ToolTestModal.tsx
18871
- function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
19942
+ // src/components/ToolTestModal.tsx
19943
+ function ToolTestModal({ tool, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
18872
19944
  const [state, setState] = useState("form");
18873
19945
  const [result, setResult] = useState(null);
18874
19946
  const [savePrompt, setSavePromptState] = useState(null);
@@ -18942,7 +20014,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
18942
20014
  }
18943
20015
  }
18944
20016
  };
18945
- useInput((input, key) => handleInputRef.current(input, key), { isActive: true });
20017
+ useInput((input, key) => handleInputRef.current(input, key), { isActive: inputActive });
18946
20018
  const openSavePrompt = () => {
18947
20019
  if (!result?.callResult) {
18948
20020
  setSaveStatus({
@@ -19014,6 +20086,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19014
20086
  }
19015
20087
  };
19016
20088
  const handleFormSubmit = async (rawValues) => {
20089
+ if (!inputActive) return;
19017
20090
  if (!inspectorClient || !tool) return;
19018
20091
  const values = decodeFormValues(inputSchema, rawValues);
19019
20092
  const missing = missingRequiredFields(inputSchema, values, rawValues);
@@ -19027,6 +20100,17 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19027
20100
  setState("results");
19028
20101
  return;
19029
20102
  }
20103
+ const outOfBounds = selectionCountErrors(inputSchema, values, rawValues);
20104
+ if (outOfBounds.length > 0) {
20105
+ setResult({
20106
+ input: values,
20107
+ output: null,
20108
+ error: `Invalid argument${outOfBounds.length > 1 ? "s" : ""}: ${outOfBounds.join("; ")}`,
20109
+ duration: 0
20110
+ });
20111
+ setState("results");
20112
+ return;
20113
+ }
19030
20114
  setState("loading");
19031
20115
  const startTime = Date.now();
19032
20116
  try {
@@ -19116,7 +20200,8 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19116
20200
  flexGrow: 1,
19117
20201
  width: "100%",
19118
20202
  children: /* @__PURE__ */ jsx(Form, {
19119
- form: formStructure,
20203
+ form: untitledForm(formStructure),
20204
+ customManagers: FORM_FIELD_MANAGERS,
19120
20205
  onSubmit: (value) => void handleFormSubmit(value)
19121
20206
  })
19122
20207
  }),
@@ -19224,8 +20309,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19224
20309
  })
19225
20310
  });
19226
20311
  }
19227
- //#endregion
19228
- //#region src/utils/uriTemplateToForm.ts
20312
+ // src/utils/uriTemplateToForm.ts
19229
20313
  function uriTemplateToForm(uriTemplate, templateName) {
19230
20314
  let fields = [];
19231
20315
  try {
@@ -19249,15 +20333,14 @@ function uriTemplateToForm(uriTemplate, templateName) {
19249
20333
  sections
19250
20334
  };
19251
20335
  }
19252
- //#endregion
19253
- //#region src/components/ResourceTestModal.tsx
20336
+ // src/components/ResourceTestModal.tsx
19254
20337
  function getErrorMessage$1(error) {
19255
20338
  if (error instanceof Error) return error.message;
19256
20339
  if (typeof error === "string") return error;
19257
20340
  if (error && typeof error === "object" && "message" in error) return String(error.message);
19258
20341
  return "Unknown error";
19259
20342
  }
19260
- function ResourceTestModal({ template, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
20343
+ function ResourceTestModal({ template, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
19261
20344
  const [state, setState] = useState("form");
19262
20345
  const [result, setResult] = useState(null);
19263
20346
  const scrollViewRef = React.useRef(null);
@@ -19304,8 +20387,9 @@ function ResourceTestModal({ template, inspectorClient, width, height, onClose,
19304
20387
  scrollViewRef.current?.scrollBy(-viewportHeight);
19305
20388
  }
19306
20389
  }
19307
- }, { isActive: true });
20390
+ }, { isActive: inputActive });
19308
20391
  const handleFormSubmit = async (values) => {
20392
+ if (!inputActive) return;
19309
20393
  if (!inspectorClient || !template) return;
19310
20394
  const unmetGroups = unmetRequiredGroups(requiredGroups(template.uriTemplate), values);
19311
20395
  if (unmetGroups.length > 0) {
@@ -19408,7 +20492,7 @@ function ResourceTestModal({ template, inspectorClient, width, height, onClose,
19408
20492
  children: template.description
19409
20493
  })
19410
20494
  }), /* @__PURE__ */ jsx(Form, {
19411
- form: formStructure,
20495
+ form: untitledForm(formStructure),
19412
20496
  onSubmit: (values) => handleFormSubmit(values)
19413
20497
  })]
19414
20498
  }),
@@ -19533,8 +20617,7 @@ function ResourceTestModal({ template, inspectorClient, width, height, onClose,
19533
20617
  })
19534
20618
  });
19535
20619
  }
19536
- //#endregion
19537
- //#region src/utils/promptArgsToForm.ts
20620
+ // src/utils/promptArgsToForm.ts
19538
20621
  function promptArgsToForm(promptArguments, promptName) {
19539
20622
  const fields = [];
19540
20623
  if (!promptArguments || promptArguments.length === 0) return {
@@ -19563,15 +20646,14 @@ function promptArgsToForm(promptArguments, promptName) {
19563
20646
  sections
19564
20647
  };
19565
20648
  }
19566
- //#endregion
19567
- //#region src/components/PromptTestModal.tsx
20649
+ // src/components/PromptTestModal.tsx
19568
20650
  function getErrorMessage(error) {
19569
20651
  if (error instanceof Error) return error.message;
19570
20652
  if (typeof error === "string") return error;
19571
20653
  if (error && typeof error === "object" && "message" in error) return String(error.message);
19572
20654
  return "Unknown error";
19573
20655
  }
19574
- function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
20656
+ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
19575
20657
  const [state, setState] = useState("form");
19576
20658
  const [result, setResult] = useState(null);
19577
20659
  const scrollViewRef = React.useRef(null);
@@ -19618,8 +20700,9 @@ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAu
19618
20700
  scrollViewRef.current?.scrollBy(-viewportHeight);
19619
20701
  }
19620
20702
  }
19621
- }, { isActive: true });
20703
+ }, { isActive: inputActive });
19622
20704
  const handleFormSubmit = async (values) => {
20705
+ if (!inputActive) return;
19623
20706
  if (!inspectorClient || !prompt) return;
19624
20707
  setState("loading");
19625
20708
  const startTime = Date.now();
@@ -19705,7 +20788,7 @@ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAu
19705
20788
  children: prompt.description
19706
20789
  })
19707
20790
  }), /* @__PURE__ */ jsx(Form, {
19708
- form: formStructure,
20791
+ form: untitledForm(formStructure),
19709
20792
  onSubmit: (values) => handleFormSubmit(values)
19710
20793
  })]
19711
20794
  }),
@@ -19818,9 +20901,8 @@ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAu
19818
20901
  })
19819
20902
  });
19820
20903
  }
19821
- //#endregion
19822
- //#region src/components/DetailsModal.tsx
19823
- function DetailsModal({ title, content, width, height, onClose, copyText }) {
20904
+ // src/components/DetailsModal.tsx
20905
+ function DetailsModal({ title, content, width, height, onClose, inputActive = true, copyText }) {
19824
20906
  const scrollViewRef = useRef(null);
19825
20907
  const { handleCopyKey, status: copyStatus } = useCopyKeys(copyText, "details");
19826
20908
  const [terminalDimensions, setTerminalDimensions] = React.useState({
@@ -19852,7 +20934,7 @@ function DetailsModal({ title, content, width, height, onClose, copyText }) {
19852
20934
  const viewportHeight = scrollViewRef.current?.getViewportHeight() || 1;
19853
20935
  scrollViewRef.current?.scrollBy(-viewportHeight);
19854
20936
  }
19855
- }, { isActive: true });
20937
+ }, { isActive: inputActive });
19856
20938
  const modalWidth = terminalDimensions.width - 2;
19857
20939
  const modalHeight = terminalDimensions.height - 2;
19858
20940
  return /* @__PURE__ */ jsx(Box, {
@@ -19909,8 +20991,7 @@ function DetailsModal({ title, content, width, height, onClose, copyText }) {
19909
20991
  })
19910
20992
  });
19911
20993
  }
19912
- //#endregion
19913
- //#region src/utils/keybindings.ts
20994
+ // src/utils/keybindings.ts
19914
20995
  function tabAcceleratorBinding(visible) {
19915
20996
  return {
19916
20997
  keys: visible.map((tab) => tab.accelerator).join(" "),
@@ -20157,10 +21238,9 @@ function keyColumnWidth(sections) {
20157
21238
  for (const section of sections) for (const binding of section.bindings) width = Math.max(width, binding.keys.length);
20158
21239
  return width;
20159
21240
  }
20160
- //#endregion
20161
- //#region src/components/HelpOverlay.tsx
21241
+ // src/components/HelpOverlay.tsx
20162
21242
  const COLUMN_GAP = 2;
20163
- function HelpOverlay({ sections, width, height, onClose }) {
21243
+ function HelpOverlay({ sections, width, height, onClose, inputActive = true }) {
20164
21244
  const scrollViewRef = useRef(null);
20165
21245
  const keysWidth = keyColumnWidth(sections) + COLUMN_GAP;
20166
21246
  useInput((input, key) => {
@@ -20170,7 +21250,7 @@ function HelpOverlay({ sections, width, height, onClose }) {
20170
21250
  else if (key.upArrow) view?.scrollBy(-1);
20171
21251
  else if (key.pageDown) view?.scrollBy(view.getViewportHeight());
20172
21252
  else if (key.pageUp) view?.scrollBy(-view.getViewportHeight());
20173
- });
21253
+ }, { isActive: inputActive });
20174
21254
  return /* @__PURE__ */ jsx(Box, {
20175
21255
  position: "absolute",
20176
21256
  width,
@@ -20229,8 +21309,7 @@ function HelpOverlay({ sections, width, height, onClose }) {
20229
21309
  })
20230
21310
  });
20231
21311
  }
20232
- //#endregion
20233
- //#region src/components/TasksTab.tsx
21312
+ // src/components/TasksTab.tsx
20234
21313
  const STATUS_STYLE = {
20235
21314
  working: {
20236
21315
  glyph: "◐",
@@ -20582,8 +21661,7 @@ function subscribableResources(resources, subscriptions) {
20582
21661
  }
20583
21662
  return rows;
20584
21663
  }
20585
- //#endregion
20586
- //#region src/components/SubscriptionsTab.tsx
21664
+ // src/components/SubscriptionsTab.tsx
20587
21665
  const STREAM_STATUS_TEXT = {
20588
21666
  connecting: {
20589
21667
  text: "connecting…",
@@ -20863,8 +21941,7 @@ function SubscriptionsTab({ resources, subscriptions, streamState, messages, ins
20863
21941
  })]
20864
21942
  });
20865
21943
  }
20866
- //#endregion
20867
- //#region src/components/RootsModal.tsx
21944
+ // src/components/RootsModal.tsx
20868
21945
  const ADD_ROOT_FORM = {
20869
21946
  title: "Add Root",
20870
21947
  sections: [{
@@ -20890,7 +21967,7 @@ function rootFromForm(values) {
20890
21967
  name
20891
21968
  } : { uri };
20892
21969
  }
20893
- function RootsModal({ roots, inspectorClient, connected, width, height, onClose }) {
21970
+ function RootsModal({ roots, inspectorClient, connected, width, height, onClose, inputActive = true }) {
20894
21971
  const [mode, setMode] = useState("list");
20895
21972
  const [error, setError] = useState(null);
20896
21973
  const [saving, setSaving] = useState(false);
@@ -20915,6 +21992,7 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
20915
21992
  }
20916
21993
  };
20917
21994
  const handleSubmit = (values) => {
21995
+ if (!inputActive) return;
20918
21996
  const root = rootFromForm(values);
20919
21997
  if ("error" in root) {
20920
21998
  setError(root.error);
@@ -20946,7 +22024,7 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
20946
22024
  }
20947
22025
  save(roots.filter((_, i) => i !== selectedIndex));
20948
22026
  }
20949
- });
22027
+ }, { isActive: inputActive });
20950
22028
  return /* @__PURE__ */ jsx(Box, {
20951
22029
  position: "absolute",
20952
22030
  width,
@@ -21057,8 +22135,468 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
21057
22135
  })
21058
22136
  });
21059
22137
  }
21060
- //#endregion
21061
- //#region src/App.tsx
22138
+ // src/utils/pendingRequests.ts
22139
+ const SAMPLING_STOP_REASONS = [
22140
+ "endTurn",
22141
+ "stopSequence",
22142
+ "maxTokens"
22143
+ ];
22144
+ const DEFAULT_SAMPLING_MODEL = "stub-model";
22145
+ const SAMPLING_RESPONSE_FORM = { sections: [{
22146
+ title: "Response",
22147
+ fields: [
22148
+ {
22149
+ type: "string",
22150
+ name: "text",
22151
+ label: "Response text"
22152
+ },
22153
+ {
22154
+ type: "string",
22155
+ name: "model",
22156
+ label: "Model",
22157
+ required: true,
22158
+ initialValue: DEFAULT_SAMPLING_MODEL
22159
+ },
22160
+ {
22161
+ type: "select",
22162
+ name: "stopReason",
22163
+ label: "Stop reason",
22164
+ required: true,
22165
+ initialValue: "endTurn",
22166
+ options: SAMPLING_STOP_REASONS.map((reason) => ({
22167
+ label: reason,
22168
+ value: reason
22169
+ }))
22170
+ }
22171
+ ]
22172
+ }] };
22173
+ function samplingResultFromForm(values) {
22174
+ const text = typeof values.text === "string" ? values.text : "";
22175
+ return {
22176
+ role: "assistant",
22177
+ model: typeof values.model === "string" && values.model.trim() !== "" ? values.model.trim() : DEFAULT_SAMPLING_MODEL,
22178
+ stopReason: typeof values.stopReason === "string" ? values.stopReason : "endTurn",
22179
+ content: {
22180
+ type: "text",
22181
+ text
22182
+ }
22183
+ };
22184
+ }
22185
+ function describeBlock(block) {
22186
+ if (typeof block !== "object" || block === null) return String(block);
22187
+ const typed = block;
22188
+ if (typed.type === "text" && typeof typed.text === "string") return typed.text;
22189
+ if (typeof typed.mimeType === "string") return `[${String(typed.type)}: ${typed.mimeType}]`;
22190
+ if (typeof typed.name === "string") return `[${String(typed.type)}: ${typed.name}]`;
22191
+ return `[${String(typed.type ?? "unknown")}]`;
22192
+ }
22193
+ function describeSamplingRequest(params) {
22194
+ const lines = [];
22195
+ if (params.systemPrompt) lines.push(`System prompt: ${params.systemPrompt}`);
22196
+ lines.push(`Max tokens: ${params.maxTokens}`);
22197
+ const hints = (params.modelPreferences?.hints ?? []).map((hint) => hint.name).filter((name) => typeof name === "string");
22198
+ if (hints.length > 0) lines.push(`Model hints: ${hints.join(", ")}`);
22199
+ lines.push("");
22200
+ for (const message of params.messages) {
22201
+ const [first = "", ...rest] = (Array.isArray(message.content) ? message.content : [message.content]).map(describeBlock).join(" ").split("\n");
22202
+ lines.push(`${message.role}: ${first}`);
22203
+ for (const line of rest) lines.push(` ${line}`);
22204
+ }
22205
+ return lines;
22206
+ }
22207
+ function constOptions(members) {
22208
+ if (!Array.isArray(members) || members.length === 0) return void 0;
22209
+ const values = [];
22210
+ const names = [];
22211
+ for (const member of members) {
22212
+ if (typeof member !== "object" || member === null) return void 0;
22213
+ const { const: value, title } = member;
22214
+ if (typeof value !== "string") return void 0;
22215
+ values.push(value);
22216
+ names.push(typeof title === "string" ? title : value);
22217
+ }
22218
+ return {
22219
+ values,
22220
+ names
22221
+ };
22222
+ }
22223
+ function normalizeElicitationSchema(schema) {
22224
+ const properties = Object.fromEntries(Object.entries(schema.properties).map(([name, property]) => {
22225
+ const { oneOf, items, ...rest } = property;
22226
+ const single = constOptions(oneOf);
22227
+ if (single) return [name, {
22228
+ ...rest,
22229
+ enum: single.values,
22230
+ enumNames: single.names
22231
+ }];
22232
+ const multi = constOptions(items?.anyOf);
22233
+ if (multi) return [name, {
22234
+ ...rest,
22235
+ items: {
22236
+ enum: multi.values,
22237
+ enumNames: multi.names
22238
+ }
22239
+ }];
22240
+ return [name, property];
22241
+ }));
22242
+ return {
22243
+ ...schema,
22244
+ properties
22245
+ };
22246
+ }
22247
+ function elicitationForm(schema) {
22248
+ const [first, ...rest] = schemaToForm(normalizeElicitationSchema(schema), "elicitation").sections;
22249
+ return { sections: [{
22250
+ ...first,
22251
+ title: "Response"
22252
+ }, ...rest] };
22253
+ }
22254
+ function elicitationContentFromForm(schema, rawValues) {
22255
+ const normalized = normalizeElicitationSchema(schema);
22256
+ const decoded = decodeFormValues(normalized, rawValues);
22257
+ const missing = missingRequiredFields(normalized, decoded, rawValues);
22258
+ if (missing.length > 0) return { missing };
22259
+ const invalid = selectionCountErrors(normalized, decoded, rawValues);
22260
+ if (invalid.length > 0) return { invalid };
22261
+ return { result: {
22262
+ action: "accept",
22263
+ content: Object.fromEntries(Object.entries(decoded).filter(([, value]) => value !== void 0 && value !== null).map(([name, value]) => {
22264
+ return [name, normalized.properties[name]?.type === "array" && typeof value === "string" ? [value] : value];
22265
+ }))
22266
+ } };
22267
+ }
22268
+ function messageBoxHeight(message, columns, terminalRows) {
22269
+ const perRow = Math.max(1, columns);
22270
+ const wrapped = message.split("\n").reduce((rows, line) => rows + Math.max(1, Math.ceil(line.length / perRow)), 0);
22271
+ return Math.max(1, Math.min(wrapped, Math.floor(terminalRows / 3)));
22272
+ }
22273
+ function elicitationUrlRefusal(url) {
22274
+ try {
22275
+ const { protocol } = new URL(url);
22276
+ if (protocol === "http:" || protocol === "https:") return void 0;
22277
+ } catch {}
22278
+ return "Refusing to open this URL: only http: and https: URLs can be opened from an elicitation request.";
22279
+ }
22280
+ // src/components/PendingRequestModal.tsx
22281
+ function useSettle(onError) {
22282
+ const busyRef = useRef(false);
22283
+ return (action) => {
22284
+ if (busyRef.current) return;
22285
+ busyRef.current = true;
22286
+ action().catch((err) => {
22287
+ busyRef.current = false;
22288
+ onError(errorMessage$1(err));
22289
+ });
22290
+ };
22291
+ }
22292
+ function useDismissPrompt() {
22293
+ const [confirming, setConfirming] = useState(false);
22294
+ const openRef = useRef(false);
22295
+ const closingRef = useRef(false);
22296
+ return {
22297
+ confirming,
22298
+ isOpen: () => openRef.current,
22299
+ open: () => {
22300
+ openRef.current = true;
22301
+ setConfirming(true);
22302
+ },
22303
+ close: () => {
22304
+ openRef.current = false;
22305
+ closingRef.current = true;
22306
+ setConfirming(false);
22307
+ setTimeout(() => {
22308
+ closingRef.current = false;
22309
+ }, 0);
22310
+ },
22311
+ submitBlocked: () => openRef.current || closingRef.current
22312
+ };
22313
+ }
22314
+ function originNote(origin, taskId) {
22315
+ if (origin === "task-input-required") return `Requested by task ${taskId ?? "(unknown)"} (input_required)`;
22316
+ if (origin === "input-required") return "Requested mid-call (input_required round)";
22317
+ return null;
22318
+ }
22319
+ function ModalFrame({ title, hint, queueLabel, note, status, width, height, children }) {
22320
+ return /* @__PURE__ */ jsx(Box, {
22321
+ position: "absolute",
22322
+ width,
22323
+ height,
22324
+ flexDirection: "column",
22325
+ justifyContent: "center",
22326
+ alignItems: "center",
22327
+ children: /* @__PURE__ */ jsxs(Box, {
22328
+ width: width - 2,
22329
+ height: height - 2,
22330
+ borderStyle: "single",
22331
+ borderColor: "yellow",
22332
+ flexDirection: "column",
22333
+ paddingX: 1,
22334
+ paddingY: 1,
22335
+ backgroundColor: "black",
22336
+ children: [
22337
+ /* @__PURE__ */ jsxs(Box, {
22338
+ flexShrink: 0,
22339
+ children: [/* @__PURE__ */ jsx(Text, {
22340
+ bold: true,
22341
+ color: "yellow",
22342
+ children: title
22343
+ }), queueLabel && /* @__PURE__ */ jsxs(Text, {
22344
+ dimColor: true,
22345
+ children: [
22346
+ " (",
22347
+ queueLabel,
22348
+ ")"
22349
+ ]
22350
+ })]
22351
+ }),
22352
+ /* @__PURE__ */ jsx(Box, {
22353
+ flexShrink: 0,
22354
+ children: /* @__PURE__ */ jsx(Text, {
22355
+ dimColor: true,
22356
+ children: hint
22357
+ })
22358
+ }),
22359
+ note && /* @__PURE__ */ jsx(Box, {
22360
+ flexShrink: 0,
22361
+ children: /* @__PURE__ */ jsx(Text, {
22362
+ dimColor: true,
22363
+ children: note
22364
+ })
22365
+ }),
22366
+ status && /* @__PURE__ */ jsx(Box, {
22367
+ flexShrink: 0,
22368
+ children: /* @__PURE__ */ jsx(Text, {
22369
+ color: "red",
22370
+ children: status
22371
+ })
22372
+ }),
22373
+ /* @__PURE__ */ jsx(Box, {
22374
+ flexGrow: 1,
22375
+ flexDirection: "column",
22376
+ overflow: "hidden",
22377
+ marginTop: 1,
22378
+ children
22379
+ })
22380
+ ]
22381
+ })
22382
+ });
22383
+ }
22384
+ function DismissPrompt({ choices }) {
22385
+ return /* @__PURE__ */ jsx(Box, {
22386
+ flexShrink: 0,
22387
+ children: /* @__PURE__ */ jsx(Text, {
22388
+ color: "yellow",
22389
+ children: choices
22390
+ })
22391
+ });
22392
+ }
22393
+ function SamplingRequest({ sample, queueLabel, width, height }) {
22394
+ const [status, setStatus] = useState(null);
22395
+ const settle = useSettle(setStatus);
22396
+ const prompt = useDismissPrompt();
22397
+ const scrollViewRef = useRef(null);
22398
+ useInput((input, key) => {
22399
+ if (prompt.isOpen()) {
22400
+ prompt.close();
22401
+ if (input === "r") settle(() => sample.reject(/* @__PURE__ */ new Error("Sampling request rejected by user.")));
22402
+ return;
22403
+ }
22404
+ if (key.escape) prompt.open();
22405
+ else if (key.pageDown) scrollViewRef.current?.scrollBy(1);
22406
+ else if (key.pageUp) scrollViewRef.current?.scrollBy(-1);
22407
+ });
22408
+ const summaryHeight = Math.max(3, Math.floor((height - 8) * .4));
22409
+ return /* @__PURE__ */ jsxs(ModalFrame, {
22410
+ title: "Sampling request",
22411
+ hint: "(Enter on Submit to approve, ESC to reject, PgUp/PgDn to scroll)",
22412
+ queueLabel,
22413
+ note: originNote(sample.origin, sample.taskId),
22414
+ status,
22415
+ width,
22416
+ height,
22417
+ children: [
22418
+ /* @__PURE__ */ jsx(Box, {
22419
+ height: summaryHeight,
22420
+ flexShrink: 0,
22421
+ flexDirection: "column",
22422
+ overflow: "hidden",
22423
+ children: /* @__PURE__ */ jsx(ScrollView, {
22424
+ ref: scrollViewRef,
22425
+ children: describeSamplingRequest(sample.request.params).map((line, idx) => /* @__PURE__ */ jsx(Text, { children: line || " " }, idx))
22426
+ })
22427
+ }),
22428
+ prompt.confirming && /* @__PURE__ */ jsx(DismissPrompt, { choices: "Reject this sampling request? r: reject any other key: back" }),
22429
+ /* @__PURE__ */ jsx(Box, {
22430
+ flexGrow: 1,
22431
+ width: "100%",
22432
+ children: /* @__PURE__ */ jsx(Form, {
22433
+ form: SAMPLING_RESPONSE_FORM,
22434
+ onSubmit: (values) => {
22435
+ if (prompt.submitBlocked()) return;
22436
+ settle(() => sample.respond(samplingResultFromForm(values)));
22437
+ }
22438
+ })
22439
+ })
22440
+ ]
22441
+ });
22442
+ }
22443
+ function settleElicitation(elicitation, result, inspectorClient) {
22444
+ if (result.action === "cancel" && elicitation.origin === "task-input-required" && elicitation.taskId && inspectorClient) return inspectorClient.cancelRequestorTask(elicitation.taskId);
22445
+ return elicitation.respond(result);
22446
+ }
22447
+ function ElicitationFormRequest({ elicitation, params, inspectorClient, queueLabel, width, height }) {
22448
+ const [status, setStatus] = useState(null);
22449
+ const settleWith = useSettle(setStatus);
22450
+ const prompt = useDismissPrompt();
22451
+ const messageRef = useRef(null);
22452
+ const [form] = useState(() => elicitationForm(params.requestedSchema));
22453
+ const settle = (result) => settleWith(() => settleElicitation(elicitation, result, inspectorClient));
22454
+ useInput((input, key) => {
22455
+ if (prompt.isOpen()) {
22456
+ prompt.close();
22457
+ if (input === "d") settle({ action: "decline" });
22458
+ else if (input === "c") settle({ action: "cancel" });
22459
+ return;
22460
+ }
22461
+ if (key.escape) prompt.open();
22462
+ else if (key.pageDown) messageRef.current?.scrollBy(1);
22463
+ else if (key.pageUp) messageRef.current?.scrollBy(-1);
22464
+ });
22465
+ const handleSubmit = (values) => {
22466
+ if (prompt.submitBlocked()) return;
22467
+ const outcome = elicitationContentFromForm(params.requestedSchema, values);
22468
+ if ("missing" in outcome) {
22469
+ setStatus(`Missing required field${outcome.missing.length > 1 ? "s" : ""}: ${outcome.missing.join(", ")}`);
22470
+ return;
22471
+ }
22472
+ if ("invalid" in outcome) {
22473
+ setStatus(`Invalid field${outcome.invalid.length > 1 ? "s" : ""}: ${outcome.invalid.join("; ")}`);
22474
+ return;
22475
+ }
22476
+ settle(outcome.result);
22477
+ };
22478
+ return /* @__PURE__ */ jsxs(ModalFrame, {
22479
+ title: "Elicitation request",
22480
+ hint: "(Enter on Submit to accept, ESC to decline or cancel, PgUp/PgDn to scroll)",
22481
+ queueLabel,
22482
+ note: originNote(elicitation.origin, elicitation.taskId),
22483
+ status,
22484
+ width,
22485
+ height,
22486
+ children: [
22487
+ /* @__PURE__ */ jsx(Box, {
22488
+ height: messageBoxHeight(params.message, width - 6, height),
22489
+ flexShrink: 0,
22490
+ flexDirection: "column",
22491
+ overflow: "hidden",
22492
+ marginBottom: 1,
22493
+ children: /* @__PURE__ */ jsx(ScrollView, {
22494
+ ref: messageRef,
22495
+ children: /* @__PURE__ */ jsx(Text, { children: params.message })
22496
+ })
22497
+ }),
22498
+ prompt.confirming && /* @__PURE__ */ jsx(DismissPrompt, { choices: "Dismiss this request? d: decline c: cancel any other key: back" }),
22499
+ /* @__PURE__ */ jsx(Box, {
22500
+ flexGrow: 1,
22501
+ width: "100%",
22502
+ children: /* @__PURE__ */ jsx(Form, {
22503
+ form,
22504
+ customManagers: FORM_FIELD_MANAGERS,
22505
+ onSubmit: (values) => handleSubmit(values)
22506
+ })
22507
+ })
22508
+ ]
22509
+ });
22510
+ }
22511
+ function ElicitationUrlRequest({ elicitation, message, url, inspectorClient, queueLabel, width, height }) {
22512
+ const [status, setStatus] = useState(null);
22513
+ const settleWith = useSettle(setStatus);
22514
+ const refusal = elicitationUrlRefusal(url);
22515
+ const messageRef = useRef(null);
22516
+ const settle = (result) => settleWith(() => settleElicitation(elicitation, result, inspectorClient));
22517
+ useInput((input, key) => {
22518
+ if (input === "o") {
22519
+ if (refusal) {
22520
+ setStatus(refusal);
22521
+ return;
22522
+ }
22523
+ openUrl(url, setStatus);
22524
+ } else if (key.return) settle({ action: "accept" });
22525
+ else if (input === "d") settle({ action: "decline" });
22526
+ else if (key.escape || input === "c") settle({ action: "cancel" });
22527
+ else if (key.pageDown) messageRef.current?.scrollBy(1);
22528
+ else if (key.pageUp) messageRef.current?.scrollBy(-1);
22529
+ });
22530
+ return /* @__PURE__ */ jsxs(ModalFrame, {
22531
+ title: "Elicitation request (URL)",
22532
+ hint: "(o: open in browser, Enter: done, d: decline, ESC: cancel, PgUp/PgDn: scroll)",
22533
+ queueLabel,
22534
+ note: originNote(elicitation.origin, elicitation.taskId),
22535
+ status,
22536
+ width,
22537
+ height,
22538
+ children: [
22539
+ /* @__PURE__ */ jsx(Box, {
22540
+ flexShrink: 0,
22541
+ marginBottom: 1,
22542
+ children: /* @__PURE__ */ jsx(Text, {
22543
+ color: "cyan",
22544
+ children: url
22545
+ })
22546
+ }),
22547
+ /* @__PURE__ */ jsx(Box, {
22548
+ height: messageBoxHeight(message, width - 6, height),
22549
+ flexShrink: 0,
22550
+ flexDirection: "column",
22551
+ overflow: "hidden",
22552
+ children: /* @__PURE__ */ jsx(ScrollView, {
22553
+ ref: messageRef,
22554
+ children: /* @__PURE__ */ jsx(Text, { children: message })
22555
+ })
22556
+ }),
22557
+ /* @__PURE__ */ jsx(Box, {
22558
+ flexShrink: 0,
22559
+ marginTop: 1,
22560
+ children: /* @__PURE__ */ jsx(Text, {
22561
+ dimColor: true,
22562
+ children: "Complete the flow in your browser, then press Enter. The Inspector cannot observe the external flow finishing."
22563
+ })
22564
+ })
22565
+ ]
22566
+ });
22567
+ }
22568
+ function PendingRequestModal({ pendingSamples, pendingElicitations, inspectorClient, width, height }) {
22569
+ const total = pendingSamples.length + pendingElicitations.length;
22570
+ const queueLabel = total > 1 ? `${total} pending` : "";
22571
+ const sample = pendingSamples[0];
22572
+ if (sample) return /* @__PURE__ */ jsx(SamplingRequest, {
22573
+ sample,
22574
+ queueLabel,
22575
+ width,
22576
+ height
22577
+ }, sample.id);
22578
+ const elicitation = pendingElicitations[0];
22579
+ if (!elicitation) return null;
22580
+ const params = elicitation.request.params;
22581
+ if (params.mode === "url") return /* @__PURE__ */ jsx(ElicitationUrlRequest, {
22582
+ elicitation,
22583
+ message: params.message,
22584
+ url: params.url,
22585
+ inspectorClient,
22586
+ queueLabel,
22587
+ width,
22588
+ height
22589
+ }, elicitation.id);
22590
+ return /* @__PURE__ */ jsx(ElicitationFormRequest, {
22591
+ elicitation,
22592
+ params,
22593
+ inspectorClient,
22594
+ queueLabel,
22595
+ width,
22596
+ height
22597
+ }, elicitation.id);
22598
+ }
22599
+ // src/App.tsx
21062
22600
  const APP_NAME = "MCP Inspector TUI";
21063
22601
  const APP_DESCRIPTION = "Terminal User Interface for the Model Context Protocol Inspector";
21064
22602
  const APP_VERSION = readInspectorVersion(import.meta.url);
@@ -21075,7 +22613,6 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21075
22613
  const [activeTab, setActiveTab] = useState("info");
21076
22614
  const [paneFocus, setFocus] = useState("serverList");
21077
22615
  const [helpOpen, setHelpOpen] = useState(false);
21078
- const focus = helpOpen ? "help" : paneFocus;
21079
22616
  const [listFilterEditing, setListFilterEditing] = useState(false);
21080
22617
  const [listFilterClaimsEscape, setListFilterClaimsEscape] = useState(false);
21081
22618
  const [tabCounts, setTabCounts] = useState({});
@@ -21178,6 +22715,11 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21178
22715
  ...defaultMetadata && Object.keys(defaultMetadata).length > 0 && { defaultMetadata },
21179
22716
  ...savedSettings && { serverSettings: savedSettings },
21180
22717
  roots: cleanRoots(savedSettings?.roots ?? []),
22718
+ sample: true,
22719
+ elicit: {
22720
+ form: true,
22721
+ url: true
22722
+ },
21181
22723
  ...savedSettings?.protocolEra && { versionNegotiation: eraToVersionNegotiation(savedSettings.protocolEra) },
21182
22724
  ...clientAuthOptions
21183
22725
  };
@@ -21333,6 +22875,9 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21333
22875
  if (activeTab === "auth" && selectedServerConfig && !isOAuthCapableServerConfig(selectedServerConfig)) setActiveTab("info");
21334
22876
  }, [activeTab, selectedServerConfig]);
21335
22877
  const selectedInspectorClient = useMemo(() => selectedServer ? inspectorClients[selectedServer] : null, [selectedServer, inspectorClients]);
22878
+ const { pendingSamples, pendingElicitations } = usePendingClientRequests(selectedInspectorClient);
22879
+ const pendingRequestOpen = pendingSamples.length + pendingElicitations.length > 0;
22880
+ const focus = helpOpen || pendingRequestOpen ? "overlay" : paneFocus;
21336
22881
  const { status: inspectorStatus, capabilities: inspectorCapabilities, serverInfo: inspectorServerInfo, instructions: inspectorInstructions, connect: connectInspector, disconnect: disconnectInspector, lastError: inspectorLastError } = useInspectorClient(selectedInspectorClient);
21337
22882
  const selectedMessageLogState = useMemo(() => selectedServer && messageLogStates[selectedServer] ? messageLogStates[selectedServer] : null, [selectedServer, messageLogStates]);
21338
22883
  const selectedFetchRequestLogState = useMemo(() => selectedServer && fetchRequestLogStates[selectedServer] ? fetchRequestLogStates[selectedServer] : null, [selectedServer, fetchRequestLogStates]);
@@ -21341,6 +22886,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21341
22886
  const { fetchRequests: inspectorFetchRequests } = useFetchRequestLog(selectedFetchRequestLogState);
21342
22887
  const { stderrLogs: inspectorStderrLogs } = useStderrLog(selectedStderrLogState);
21343
22888
  const { tools: managedTools } = useManagedTools(selectedInspectorClient, useMemo(() => selectedServer && managedToolsStates[selectedServer] ? managedToolsStates[selectedServer] : null, [selectedServer, managedToolsStates]));
22889
+ const sortedTools = useMemo(() => [...managedTools].sort(compareToolsByName), [managedTools]);
21344
22890
  const selectedManagedResourcesState = useMemo(() => selectedServer && managedResourcesStates[selectedServer] ? managedResourcesStates[selectedServer] : null, [selectedServer, managedResourcesStates]);
21345
22891
  const selectedManagedResourceTemplatesState = useMemo(() => selectedServer && managedResourceTemplatesStates[selectedServer] ? managedResourceTemplatesStates[selectedServer] : null, [selectedServer, managedResourceTemplatesStates]);
21346
22892
  const selectedManagedPromptsState = useMemo(() => selectedServer && managedPromptsStates[selectedServer] ? managedPromptsStates[selectedServer] : null, [selectedServer, managedPromptsStates]);
@@ -21640,7 +23186,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21640
23186
  resources: managedResources,
21641
23187
  resourceTemplates: managedResourceTemplates,
21642
23188
  prompts: managedPrompts,
21643
- tools: managedTools,
23189
+ tools: sortedTools,
21644
23190
  stderrLogs: inspectorStderrLogs
21645
23191
  };
21646
23192
  }, [
@@ -21654,7 +23200,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21654
23200
  managedResources,
21655
23201
  managedResourceTemplates,
21656
23202
  managedPrompts,
21657
- managedTools,
23203
+ sortedTools,
21658
23204
  inspectorStderrLogs
21659
23205
  ]);
21660
23206
  const renderResourceDetails = (resource) => /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -22041,7 +23587,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22041
23587
  inspectorClients
22042
23588
  ]);
22043
23589
  useInput((input, key) => {
22044
- if (toolTestModal || resourceTestModal || promptTestModal || detailsModal || helpOpen || rootsModalOpen) return;
23590
+ if (toolTestModal || resourceTestModal || promptTestModal || detailsModal || helpOpen || rootsModalOpen || pendingRequestOpen) return;
22045
23591
  if (key.ctrl && input === "c") exit();
22046
23592
  if (listFilterEditing) return;
22047
23593
  if (input === "?") {
@@ -22668,6 +24214,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22668
24214
  width: dimensions.width,
22669
24215
  height: dimensions.height,
22670
24216
  onClose: () => setToolTestModal(null),
24217
+ inputActive: !pendingRequestOpen,
22671
24218
  onAuthRecoveryRequired: (error) => {
22672
24219
  onAuthRecoveryRequired(error);
22673
24220
  setToolTestModal(null);
@@ -22679,6 +24226,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22679
24226
  width: dimensions.width,
22680
24227
  height: dimensions.height,
22681
24228
  onClose: () => setResourceTestModal(null),
24229
+ inputActive: !pendingRequestOpen,
22682
24230
  onAuthRecoveryRequired: (error) => {
22683
24231
  onAuthRecoveryRequired(error);
22684
24232
  setResourceTestModal(null);
@@ -22690,6 +24238,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22690
24238
  width: dimensions.width,
22691
24239
  height: dimensions.height,
22692
24240
  onClose: () => setPromptTestModal(null),
24241
+ inputActive: !pendingRequestOpen,
22693
24242
  onAuthRecoveryRequired: (error) => {
22694
24243
  onAuthRecoveryRequired(error);
22695
24244
  setPromptTestModal(null);
@@ -22699,7 +24248,8 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22699
24248
  sections: keybindingSections(activeTab, shownTabs),
22700
24249
  width: dimensions.width,
22701
24250
  height: dimensions.height,
22702
- onClose: () => setHelpOpen(false)
24251
+ onClose: () => setHelpOpen(false),
24252
+ inputActive: !pendingRequestOpen
22703
24253
  }),
22704
24254
  rootsModalOpen && /* @__PURE__ */ jsx(RootsModal, {
22705
24255
  roots: advertisedRoots,
@@ -22707,7 +24257,8 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22707
24257
  connected: inspectorStatus === "connected",
22708
24258
  width: dimensions.width,
22709
24259
  height: dimensions.height,
22710
- onClose: () => setRootsModalOpen(false)
24260
+ onClose: () => setRootsModalOpen(false),
24261
+ inputActive: !pendingRequestOpen
22711
24262
  }),
22712
24263
  detailsModal && !helpOpen && /* @__PURE__ */ jsx(DetailsModal, {
22713
24264
  title: detailsModal.title,
@@ -22715,13 +24266,20 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22715
24266
  width: dimensions.width,
22716
24267
  height: dimensions.height,
22717
24268
  onClose: () => setDetailsModal(null),
22718
- copyText: detailsModal.copyText
24269
+ copyText: detailsModal.copyText,
24270
+ inputActive: !pendingRequestOpen
24271
+ }),
24272
+ /* @__PURE__ */ jsx(PendingRequestModal, {
24273
+ pendingSamples,
24274
+ pendingElicitations,
24275
+ inspectorClient: selectedInspectorClient,
24276
+ width: dimensions.width,
24277
+ height: dimensions.height
22719
24278
  })
22720
24279
  ]
22721
24280
  });
22722
24281
  }
22723
- //#endregion
22724
- //#region tui.tsx
24282
+ // tui.tsx
22725
24283
  async function runTui(args) {
22726
24284
  const program = new Command();
22727
24285
  program.name("mcp-inspector-tui").description("Terminal UI for MCP Inspector").version(readInspectorVersion(import.meta.url), "-V, --version", "Print the Inspector version").option("--catalog <path>", "Writable catalog file (created if missing; default: ~/.mcp-inspector/mcp.json, or MCP_CATALOG_PATH)").option("--config <path>", "Read-only session config file (served as-is, never written or seeded; errors if absent)").option("-e <key=value...>", "Environment variables for stdio servers", parseKeyValuePair, {}).option("--cwd <path>", "Working directory for stdio servers").option("--header <header...>", "HTTP headers as \"Name: Value\"", parseHeaderPair, {}).option("--protocol-era <era>", "Protocol era to negotiate: legacy, auto, or modern (overrides the file's protocolEra; default legacy)", parseProtocolEra).option("--skill-catalog-max-skills <n>", "Skills catalog budget: the most skills one multi-skill verification run reads (positive integer; overrides the file's skillCatalogMaxSkills; default 256). Bounds the Skills pane's v (verify all); Enter verifies one skill in full", skillCatalogLimitParser("--skill-catalog-max-skills")).option("--skill-catalog-max-bytes <n>", "Skills catalog budget: the most bytes one multi-skill verification run reads (positive integer; overrides the file's skillCatalogMaxBytes; default 64 MiB). Bounds the Skills pane's v (verify all); Enter verifies one skill in full", skillCatalogLimitParser("--skill-catalog-max-bytes")).option("--client-id <id>", "OAuth client ID (static client) for HTTP servers").option("--client-secret <secret>", "OAuth client secret (for confidential clients)").option("--client-metadata-url <url>", "OAuth Client ID Metadata Document URL (CIMD) for HTTP servers").option("--client-config <path>", "Install-level client config (default: ~/.mcp-inspector/storage/client.json, or MCP_CLIENT_CONFIG_PATH)").option("--callback-url <url>", `OAuth redirect/callback listener URL; must be loopback (default: ${DEFAULT_RUNNER_OAUTH_CALLBACK_URL}, or MCP_OAUTH_CALLBACK_URL)`).argument("[target...]", "Command and args or URL for a single ad-hoc server (when not using --config)").option("--transport <type>", "Transport: stdio, sse, or http (ad-hoc only)").option("--server-url <url>", "Server URL (ad-hoc only)").parse(args ?? process.argv);
@@ -22776,8 +24334,7 @@ async function runTui(args) {
22776
24334
  process.exit(1);
22777
24335
  }
22778
24336
  }
22779
- //#endregion
22780
- //#region index.ts
24337
+ // index.ts
22781
24338
  const __filename = fileURLToPath(import.meta.url);
22782
24339
  if (process.argv[1] !== void 0 && resolve(process.argv[1]) === resolve(__filename)) runTui(process.argv).catch((err) => {
22783
24340
  console.error("Error:", err instanceof Error ? err.message : err);
@@ -22788,5 +24345,4 @@ if (process.argv[1] !== void 0 && resolve(process.argv[1]) === resolve(__filenam
22788
24345
  if ((debugOn(process.env.MCP_DEBUG) || debugOn(process.env.DEBUG)) && err instanceof Error) console.error(err.stack);
22789
24346
  process.exit(1);
22790
24347
  });
22791
- //#endregion
22792
24348
  export { runTui };