@modelcontextprotocol/inspector 2.14.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.
@@ -43,15 +43,14 @@ import os from "node:os";
43
43
  import process$1 from "node:process";
44
44
  import tty from "node:tty";
45
45
  import { isDeepStrictEqual } from "node:util";
46
- //#region ../../core/storage/store-serialize.ts
46
+ // ../../core/storage/store-serialize.ts
47
47
  function serializeStore(data) {
48
48
  return JSON.stringify(data, null, 2);
49
49
  }
50
50
  function parseStore(raw) {
51
51
  return JSON.parse(raw);
52
52
  }
53
- //#endregion
54
- //#region ../../core/storage/store-io.ts
53
+ // ../../core/storage/store-io.ts
55
54
  function getDefaultStorageDir() {
56
55
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
57
56
  return path$1.join(homeDir, ".mcp-inspector", "storage");
@@ -97,8 +96,7 @@ async function deleteStoreFile(filePath) {
97
96
  if (error.code !== "ENOENT") throw error;
98
97
  }
99
98
  }
100
- //#endregion
101
- //#region ../../core/mcp/types.ts
99
+ // ../../core/mcp/types.ts
102
100
  function isTerminalStatus(status) {
103
101
  return status === "disconnected" || status === "error";
104
102
  }
@@ -136,8 +134,7 @@ function eraToVersionNegotiation(era) {
136
134
  case "legacy": return { mode: "legacy" };
137
135
  }
138
136
  }
139
- //#endregion
140
- //#region ../../core/extension/skills/schemas.ts
137
+ // ../../core/extension/skills/schemas.ts
141
138
  const CACHE_FIELDS = {
142
139
  ttlMs: ReadResourceDirectoryResultSchema.shape.ttlMs,
143
140
  cacheScope: SkillCacheScopeSchema
@@ -170,8 +167,7 @@ const DirectoryReadResultSchema = ReadResourceDirectoryResultSchema.partial({
170
167
  ttlMs: true,
171
168
  cacheScope: true
172
169
  });
173
- //#endregion
174
- //#region ../../core/extension/skills/sha256.ts
170
+ // ../../core/extension/skills/sha256.ts
175
171
  const K = new Uint32Array([
176
172
  1116352408,
177
173
  1899447441,
@@ -297,8 +293,7 @@ function sha256Bytes(bytes) {
297
293
  for (let i = 0; i < 8; i += 1) out.setUint32(i * 4, h[i]);
298
294
  return digest;
299
295
  }
300
- //#endregion
301
- //#region ../../core/extension/skills/skillFile.ts
296
+ // ../../core/extension/skills/skillFile.ts
302
297
  function splitSkillFile(text) {
303
298
  if (!/^---[ \t]*\r?\n/.test(text)) return { body: text };
304
299
  const rest = text.slice(text.indexOf("\n") + 1);
@@ -346,8 +341,7 @@ function parseSkillFrontmatter(yamlText) {
346
341
  if (graphError) return { error: graphError };
347
342
  return { fields: parsed };
348
343
  }
349
- //#endregion
350
- //#region ../../core/extension/skills/conformance.ts
344
+ // ../../core/extension/skills/conformance.ts
351
345
  const SKILL_MAX_RESOURCE_ENTRIES = SKILL_LIMITS.files;
352
346
  const SKILL_MAX_TOTAL_BYTES = SKILL_LIMITS.bytes;
353
347
  const SKILL_MAX_CATALOG_BYTES = 67108864;
@@ -705,13 +699,11 @@ function checkSkillNameCollisions(entries) {
705
699
  }
706
700
  return issues;
707
701
  }
708
- //#endregion
709
- //#region ../../core/auth/secret-fields.ts
702
+ // ../../core/auth/secret-fields.ts
710
703
  const SECRET_FIELD_OAUTH_CLIENT_SECRET = "oauth-client-secret";
711
704
  const SECRET_FIELD_IDP_CLIENT_SECRET = "idp-client-secret";
712
705
  const envSecretField = (envKey) => `env:${envKey}`;
713
- //#endregion
714
- //#region ../../core/json/localRefs.ts
706
+ // ../../core/json/localRefs.ts
715
707
  const SUBSCHEMA_KEYWORDS$1 = /* @__PURE__ */ new Set([
716
708
  "items",
717
709
  "contains",
@@ -866,8 +858,7 @@ function inlineLocalRefs(schema) {
866
858
  cache.set(schema, resolved);
867
859
  return resolved;
868
860
  }
869
- //#endregion
870
- //#region ../../core/json/nullableUnion.ts
861
+ // ../../core/json/nullableUnion.ts
871
862
  const RENDERABLE_TYPES = [
872
863
  "string",
873
864
  "number",
@@ -1020,8 +1011,7 @@ function normalizeNullableUnion(schema) {
1020
1011
  }
1021
1012
  return schema;
1022
1013
  }
1023
- //#endregion
1024
- //#region ../../core/json/rootUnion.ts
1014
+ // ../../core/json/rootUnion.ts
1025
1015
  function membersOf(value) {
1026
1016
  return Array.isArray(value) ? value : [];
1027
1017
  }
@@ -1241,8 +1231,7 @@ function narrowBySuppliedNames(branches, candidates, suppliedNames) {
1241
1231
  const named = new Set(suppliedNames.map((name) => exclusiveTo.get(name)).filter((index) => index !== void 0 && index >= 0));
1242
1232
  return named.size === 1 ? [...named][0] : null;
1243
1233
  }
1244
- //#endregion
1245
- //#region ../../core/json/jsonUtils.ts
1234
+ // ../../core/json/jsonUtils.ts
1246
1235
  function isSerializableJson(value) {
1247
1236
  if (value === null) return true;
1248
1237
  switch (typeof value) {
@@ -1343,8 +1332,7 @@ function convertPromptArguments(args) {
1343
1332
  else stringArgs[key] = JSON.stringify(value);
1344
1333
  return stringArgs;
1345
1334
  }
1346
- //#endregion
1347
- //#region ../../core/mcp/serverList.ts
1335
+ // ../../core/mcp/serverList.ts
1348
1336
  const VALID_SERVER_TYPES = /* @__PURE__ */ new Set([
1349
1337
  "stdio",
1350
1338
  "sse",
@@ -1618,8 +1606,7 @@ function adHocServerName(config) {
1618
1606
  }
1619
1607
  return config.command?.split(/[\\/]/).pop() || "server";
1620
1608
  }
1621
- //#endregion
1622
- //#region ../../core/storage/own-entry.ts
1609
+ // ../../core/storage/own-entry.ts
1623
1610
  function setOwnEntry(map, key, value) {
1624
1611
  Object.defineProperty(map, key, {
1625
1612
  value,
@@ -1631,8 +1618,7 @@ function setOwnEntry(map, key, value) {
1631
1618
  function getOwnEntry(map, key) {
1632
1619
  return map !== void 0 && Object.hasOwn(map, key) ? map[key] : void 0;
1633
1620
  }
1634
- //#endregion
1635
- //#region ../../core/mcp/node/config.ts
1621
+ // ../../core/mcp/node/config.ts
1636
1622
  function parseKeyValuePair(value, previous = {}) {
1637
1623
  const parts = value.split("=");
1638
1624
  const key = parts[0] ?? "";
@@ -1823,8 +1809,7 @@ function resolveServerConfigs(options, mode) {
1823
1809
  }
1824
1810
  return [];
1825
1811
  }
1826
- //#endregion
1827
- //#region ../../core/auth/secret-storage-info.ts
1812
+ // ../../core/auth/secret-storage-info.ts
1828
1813
  function secretStorageLabel(info) {
1829
1814
  switch (info.kind) {
1830
1815
  case "keyring": return "OS keychain";
@@ -1851,8 +1836,7 @@ function secretStorageSummary(info) {
1851
1836
  if (info.reason === "fallback") parts.push("— fell back from the OS keychain");
1852
1837
  return parts.join(" ");
1853
1838
  }
1854
- //#endregion
1855
- //#region ../../core/auth/node/secret-store.ts
1839
+ // ../../core/auth/node/secret-store.ts
1856
1840
  const SERVICE_NAME = "mcp-inspector";
1857
1841
  let keyringLoad;
1858
1842
  var KeyringModuleShapeError = class extends Error {
@@ -2072,8 +2056,7 @@ var SessionSecretStore = class extends InMemorySecretStore {
2072
2056
  return false;
2073
2057
  }
2074
2058
  };
2075
- //#endregion
2076
- //#region ../../core/auth/node/file-lock.ts
2059
+ // ../../core/auth/node/file-lock.ts
2077
2060
  const STALE_MS = 1e4;
2078
2061
  const RETRY = {
2079
2062
  retries: 20,
@@ -2205,8 +2188,7 @@ async function withSecretFileLock(filePath, fn) {
2205
2188
  await release();
2206
2189
  }
2207
2190
  }
2208
- //#endregion
2209
- //#region ../../core/auth/node/file-secret-store.ts
2191
+ // ../../core/auth/node/file-secret-store.ts
2210
2192
  const scrypt = (passphrase, salt, keylen, options) => new Promise((resolve, reject) => {
2211
2193
  crypto$1.scrypt(passphrase, salt, keylen, options, (err, key) => {
2212
2194
  /* v8 ignore next -- @preserve: node validates the cost parameters
@@ -2614,8 +2596,7 @@ async function readSecretFilePermissions(filePath) {
2614
2596
  };
2615
2597
  }
2616
2598
  }
2617
- //#endregion
2618
- //#region ../../core/auth/node/secret-store-selection.ts
2599
+ // ../../core/auth/node/secret-store-selection.ts
2619
2600
  const SECRET_STORE_ENV = "MCP_INSPECTOR_SECRET_STORE";
2620
2601
  const SECRET_FILE_ENV = "MCP_INSPECTOR_SECRET_FILE";
2621
2602
  const STORAGE_DIR_ENV = "MCP_STORAGE_DIR";
@@ -2922,8 +2903,7 @@ function defaultSecretStore() {
2922
2903
  async function resolveConcreteSecretStore(store) {
2923
2904
  return store instanceof DeferredSecretStore ? (await resolveSecretStore()).store : store;
2924
2905
  }
2925
- //#endregion
2926
- //#region ../../core/mcp/node/server-secrets.ts
2906
+ // ../../core/mcp/node/server-secrets.ts
2927
2907
  async function rehydrateMcpConfigFromKeychain(config, secretStore) {
2928
2908
  const entries = Object.entries(config.mcpServers);
2929
2909
  const secrets = await secretStoreGetMany(secretStore, entries.map(([serverId, stored]) => ({
@@ -2934,8 +2914,7 @@ async function rehydrateMcpConfigFromKeychain(config, secretStore) {
2934
2914
  for (const [id, stored] of entries) out.mcpServers[id] = mergeSecretsIntoStored(stored, secrets[id] ?? {});
2935
2915
  return out;
2936
2916
  }
2937
- //#endregion
2938
- //#region ../../core/mcp/node/servers.ts
2917
+ // ../../core/mcp/node/servers.ts
2939
2918
  function headersToServerSettings(headers) {
2940
2919
  if (!headers || Object.keys(headers).length === 0) return;
2941
2920
  return {
@@ -3013,8 +2992,7 @@ async function loadServerEntries(serverOptions) {
3013
2992
  settings: mergeSettings(void 0, serverOptions)
3014
2993
  } };
3015
2994
  }
3016
- //#endregion
3017
- //#region ../../core/mcp/config.ts
2995
+ // ../../core/mcp/config.ts
3018
2996
  function getServerType(config) {
3019
2997
  if (!("type" in config) || config.type === void 0) return "stdio";
3020
2998
  const type = config.type;
@@ -3023,8 +3001,7 @@ function getServerType(config) {
3023
3001
  if (type === "streamable-http") return "streamable-http";
3024
3002
  throw new Error(`Invalid server type: ${type}. Valid types are: stdio, sse, streamable-http`);
3025
3003
  }
3026
- //#endregion
3027
- //#region ../../core/mcp/fetchTracking.ts
3004
+ // ../../core/mcp/fetchTracking.ts
3028
3005
  const SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
3029
3006
  "authorization",
3030
3007
  "cookie",
@@ -3077,6 +3054,37 @@ function redactUrlQuery(url) {
3077
3054
  }
3078
3055
  }
3079
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
+ }
3080
3088
  const TRAILING_PUNCTUATION = /* @__PURE__ */ new Set([
3081
3089
  ".",
3082
3090
  ",",
@@ -3094,10 +3102,37 @@ function trailingPunctuationStart(match) {
3094
3102
  return end;
3095
3103
  }
3096
3104
  function redactUrlsInText(text) {
3097
- return text.replace(EMBEDDED_URL_PATTERN, (match) => {
3098
- const end = trailingPunctuationStart(match);
3099
- return redactUrlQuery(match.slice(0, end)) + match.slice(end);
3100
- });
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);
3101
3136
  }
3102
3137
  function redactJsonValue(value) {
3103
3138
  if (Array.isArray(value)) return value.map(redactJsonValue);
@@ -3156,14 +3191,15 @@ function isLongLivedStreamResponse(method, contentType) {
3156
3191
  }
3157
3192
  const CHALLENGE_BODY_MAX_BYTES = 65536;
3158
3193
  const CHALLENGE_BODY_READ_MS = 2e3;
3194
+ const TRACKED_BODY_MAX_BYTES = 1048576;
3159
3195
  const TRUNCATED_BODY_SUFFIX = "\n[truncated]";
3160
3196
  const WITHHELD_TRUNCATED_JSON_BODY = "[truncated JSON body withheld: an incomplete body cannot be redacted]";
3161
- function recordableChallengeBody(read, contentType) {
3197
+ function recordableBody(read, contentType) {
3162
3198
  if (!read.truncated) return redactBody(read.text, contentType);
3163
3199
  if ((contentType ?? "").toLowerCase().includes("json") || /^\s*[{[]/.test(read.text)) return WITHHELD_TRUNCATED_JSON_BODY;
3164
3200
  return redactBody(read.text, contentType) + TRUNCATED_BODY_SUFFIX;
3165
3201
  }
3166
- async function readChallengeBody(response) {
3202
+ async function readCappedBody(response, maxBytes, timeoutMs) {
3167
3203
  let reader;
3168
3204
  try {
3169
3205
  const body = response.clone().body;
@@ -3177,20 +3213,23 @@ async function readChallengeBody(response) {
3177
3213
  let text = "";
3178
3214
  let bytes = 0;
3179
3215
  let timer;
3180
- const deadline = new Promise((resolve) => {
3181
- 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);
3182
3218
  });
3183
3219
  try {
3184
- while (bytes < CHALLENGE_BODY_MAX_BYTES) {
3185
- const next = await Promise.race([reader.read(), deadline]);
3220
+ for (;;) {
3221
+ const next = await (deadline ? Promise.race([reader.read(), deadline]) : reader.read());
3186
3222
  if (next === "timeout") break;
3187
3223
  if (next.done) return {
3188
3224
  text: text + decoder.decode(),
3189
3225
  truncated: false
3190
3226
  };
3191
- 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);
3192
3230
  bytes += chunk.byteLength;
3193
3231
  text += decoder.decode(chunk, { stream: true });
3232
+ if (chunk.byteLength < next.value.byteLength) break;
3194
3233
  }
3195
3234
  reader.cancel().catch(() => {});
3196
3235
  return {
@@ -3203,6 +3242,9 @@ async function readChallengeBody(response) {
3203
3242
  clearTimeout(timer);
3204
3243
  }
3205
3244
  }
3245
+ function readChallengeBody(response) {
3246
+ return readCappedBody(response, CHALLENGE_BODY_MAX_BYTES, CHALLENGE_BODY_READ_MS);
3247
+ }
3206
3248
  function longLivedStreamFraming(contentType) {
3207
3249
  return contentType?.toLowerCase().includes("application/x-ndjson") ? "ndjson" : "sse";
3208
3250
  }
@@ -3368,7 +3410,7 @@ function createFetchTracker(baseFetch, callbacks) {
3368
3410
  };
3369
3411
  if ((responseStatus === 401 || responseStatus === 403) && response.body && !response.bodyUsed) {
3370
3412
  const read = await readChallengeBody(response);
3371
- 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"));
3372
3414
  callbacks.trackRequest?.(entry);
3373
3415
  return response;
3374
3416
  }
@@ -3376,17 +3418,17 @@ function createFetchTracker(baseFetch, callbacks) {
3376
3418
  if (isLongLivedStream && response.body && !response.bodyUsed) watchLongLivedStream(response, id, longLivedStreamFraming(response.headers.get("content-type")), callbacks);
3377
3419
  if (!isLongLivedStream && response.body && !response.bodyUsed) {
3378
3420
  const responseContentType = response.headers.get("content-type");
3379
- try {
3380
- response.clone().text().then((body) => {
3381
- callbacks.updateResponseBody?.(id, redactBody(body, responseContentType) ?? body);
3382
- }).catch(() => {});
3383
- } 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
+ });
3384
3427
  }
3385
3428
  return response;
3386
3429
  };
3387
3430
  }
3388
- //#endregion
3389
- //#region ../../core/auth/utils.ts
3431
+ // ../../core/auth/utils.ts
3390
3432
  function parseHttpUrl(value, label) {
3391
3433
  const trimmed = value.trim();
3392
3434
  try {
@@ -3465,8 +3507,7 @@ function isUnauthorizedErrorDeep(err, seen) {
3465
3507
  if (data !== null && typeof data === "object" && "cause" in data && isUnauthorizedErrorDeep(data.cause, seen)) return true;
3466
3508
  return false;
3467
3509
  }
3468
- //#endregion
3469
- //#region ../../core/auth/challenge.ts
3510
+ // ../../core/auth/challenge.ts
3470
3511
  const EMA_STEP_UP_PENDING_URL = new URL("mcp-inspector:ema-step-up");
3471
3512
  var AuthChallengeError = class extends Error {
3472
3513
  authChallenge;
@@ -3612,8 +3653,7 @@ function isAuthChallengeError(err) {
3612
3653
  const wwwAuthenticate = authChallenge?.raw?.wwwAuthenticate ?? err.wwwAuthenticate ?? err.headers?.get?.("WWW-Authenticate") ?? void 0;
3613
3654
  return wwwAuthenticate !== void 0 && wwwAuthenticate.length > 0;
3614
3655
  }
3615
- //#endregion
3616
- //#region ../../core/mcp/node/authChallengeFetch.ts
3656
+ // ../../core/mcp/node/authChallengeFetch.ts
3617
3657
  function createAuthChallengeInterceptFetch(baseFetch) {
3618
3658
  return async (input, init) => {
3619
3659
  const response = await baseFetch(input, init);
@@ -3634,8 +3674,7 @@ function createAuthChallengeObserverFetch(baseFetch, onChallenge) {
3634
3674
  return response;
3635
3675
  };
3636
3676
  }
3637
- //#endregion
3638
- //#region ../../core/mcp/node/proxyFetch.ts
3677
+ // ../../core/mcp/node/proxyFetch.ts
3639
3678
  function asUndiciInit(init) {
3640
3679
  return init;
3641
3680
  }
@@ -3725,8 +3764,7 @@ function createProxyFetch() {
3725
3764
  return (await loadedProxiedFetch)(input, init);
3726
3765
  };
3727
3766
  }
3728
- //#endregion
3729
- //#region ../../core/auth/requestTimeout.ts
3767
+ // ../../core/auth/requestTimeout.ts
3730
3768
  const DEFAULT_OAUTH_REQUEST_TIMEOUT_MS = 3e4;
3731
3769
  var OAuthRequestTimeoutError = class extends Error {
3732
3770
  url;
@@ -3854,11 +3892,39 @@ function withOAuthRequestTimeout(fetchFn, timeoutMs = DEFAULT_OAUTH_REQUEST_TIME
3854
3892
  }
3855
3893
  };
3856
3894
  }
3857
- //#endregion
3858
- //#region ../../core/mcp/node/fetchGuard.ts
3895
+ // ../../core/auth/fetchRefusal.ts
3859
3896
  var FetchTargetError = class extends Error {
3860
3897
  name = "FetchTargetError";
3898
+ url;
3899
+ constructor(message, url) {
3900
+ super(message);
3901
+ if (url !== void 0) this.url = url;
3902
+ }
3861
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
+ }
3862
3928
  const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
3863
3929
  301,
3864
3930
  302,
@@ -3867,11 +3933,12 @@ const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
3867
3933
  308
3868
3934
  ]);
3869
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"]);
3870
3937
  function isBlockedAddress(ip) {
3871
3938
  const kind = isIP(ip);
3872
3939
  if (kind === 4) {
3873
3940
  const [a, b] = ip.split(".").map(Number);
3874
- return a === 169 && b === 254;
3941
+ return a === 169 && b === 254 || METADATA_IPV4_ADDRESSES.has(ip);
3875
3942
  }
3876
3943
  if (kind !== 6) return false;
3877
3944
  const addr = ip.toLowerCase();
@@ -4028,27 +4095,35 @@ async function guardedFetch(url, init, options = {}) {
4028
4095
  headers: init.headers
4029
4096
  };
4030
4097
  for (let hop = 0; hop <= 5; hop++) {
4031
- await assertAllowedTarget(request.url, resolveHost, viaProxy, init.signal);
4032
- const res = await fetchFn(request.url.href, {
4033
- method: request.method,
4034
- headers: new Headers(request.headers),
4035
- body: request.body,
4036
- signal: init.signal,
4037
- redirect: "manual"
4038
- });
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
+ }
4039
4112
  const location = res.headers.get("location");
4040
4113
  if (!REDIRECT_STATUSES.has(res.status) || location === null) return res;
4041
4114
  res.body?.cancel().catch(() => {});
4042
- 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
+ }
4043
4121
  }
4044
- throw new FetchTargetError(`Refusing to follow more than 5 redirects`);
4122
+ throw new FetchTargetError(`Refusing to follow more than 5 redirects`, request.url.href);
4045
4123
  }
4046
- function findFetchTargetError(err) {
4047
- let current = err;
4048
- for (let depth = 0; depth < 8 && current instanceof Error; depth++) {
4049
- if (current instanceof FetchTargetError) return current;
4050
- current = current.cause;
4051
- }
4124
+ function stampRefusedUrl(err, url) {
4125
+ const refused = findFetchTargetError(err);
4126
+ if (refused && refused.url === void 0) refused.url = url.href;
4052
4127
  }
4053
4128
  async function bodyText(input, init) {
4054
4129
  const body = init?.body !== void 0 ? init.body : input instanceof Request && input.body !== null ? await input.clone().text() : void 0;
@@ -4075,8 +4150,7 @@ function createGuardedFetch(options = {}) {
4075
4150
  }
4076
4151
  };
4077
4152
  }
4078
- //#endregion
4079
- //#region ../../core/auth/routeOAuthRequests.ts
4153
+ // ../../core/auth/routeOAuthRequests.ts
4080
4154
  function isJsonRpcMessage(value) {
4081
4155
  return typeof value === "object" && value !== null && value.jsonrpc === "2.0";
4082
4156
  }
@@ -4100,8 +4174,7 @@ function isMcpShapedRequest(input, init) {
4100
4174
  function routeOAuthRequests(mcpFetch, oauthFetch, isMcpEndpoint) {
4101
4175
  return (input, init) => isMcpShapedRequest(input, init) && isMcpEndpoint(requestUrlOf$2(input), requestHeadersOf(input, init)) ? mcpFetch(input, init) : oauthFetch(input, init);
4102
4176
  }
4103
- //#endregion
4104
- //#region ../../core/mcp/node/notificationHeadersFetch.ts
4177
+ // ../../core/mcp/node/notificationHeadersFetch.ts
4105
4178
  function createNotificationHeadersFetch(baseFetch) {
4106
4179
  return (input, init) => {
4107
4180
  const method = modernNotificationMethod(init);
@@ -4137,8 +4210,7 @@ function modernNotificationMethod(init) {
4137
4210
  function isRecord$4(value) {
4138
4211
  return typeof value === "object" && value !== null && !Array.isArray(value);
4139
4212
  }
4140
- //#endregion
4141
- //#region ../../core/mcp/node/suppressNotificationStreamFetch.ts
4213
+ // ../../core/mcp/node/suppressNotificationStreamFetch.ts
4142
4214
  function createSuppressNotificationStreamFetch(baseFetch, endpoint) {
4143
4215
  return async (input, init) => {
4144
4216
  if (isStandaloneStreamRequest(input, init, endpoint)) return new Response(null, {
@@ -4164,8 +4236,7 @@ function isStandaloneStreamRequest(input, init, endpoint) {
4164
4236
  const headers = new Headers(init?.headers ?? request?.headers);
4165
4237
  return (headers.get("accept")?.toLowerCase() ?? "").includes("text/event-stream") && !headers.has("last-event-id");
4166
4238
  }
4167
- //#endregion
4168
- //#region ../../core/mcp/node/transport.ts
4239
+ // ../../core/mcp/node/transport.ts
4169
4240
  function headersFromSettings(settings) {
4170
4241
  if (!settings || settings.headers.length === 0) return void 0;
4171
4242
  const out = {};
@@ -4247,8 +4318,7 @@ function createTransportNode(config, options = {}) {
4247
4318
  }) };
4248
4319
  }
4249
4320
  }
4250
- //#endregion
4251
- //#region ../../core/client/config-parse.ts
4321
+ // ../../core/client/config-parse.ts
4252
4322
  function isAbsoluteHttpUrl(value) {
4253
4323
  let url;
4254
4324
  try {
@@ -4331,8 +4401,7 @@ const ClientConfigSchema = z$1.object({
4331
4401
  function parseClientConfig(raw) {
4332
4402
  return ClientConfigSchema.parse(raw);
4333
4403
  }
4334
- //#endregion
4335
- //#region ../../core/client/secrets.ts
4404
+ // ../../core/client/secrets.ts
4336
4405
  const CLIENT_KEYCHAIN_ID = "client";
4337
4406
  function hasClientPlaintextSecret(config) {
4338
4407
  const secret = config.enterpriseManagedAuth?.idp?.clientSecret;
@@ -4373,8 +4442,7 @@ function mergeSecretsIntoClientConfig(config, secrets) {
4373
4442
  }
4374
4443
  };
4375
4444
  }
4376
- //#endregion
4377
- //#region ../../core/client/node-persistence.ts
4445
+ // ../../core/client/node-persistence.ts
4378
4446
  async function withClientConfigLock(filePath, action, body) {
4379
4447
  let entered = false;
4380
4448
  try {
@@ -4424,8 +4492,7 @@ async function readClientConfigStore(filePath, secretStore) {
4424
4492
  const secrets = await readIdpSecretFromKeychain(secretStore);
4425
4493
  return mergeSecretsIntoClientConfig(config, secrets);
4426
4494
  }
4427
- //#endregion
4428
- //#region ../../core/client/config.ts
4495
+ // ../../core/client/config.ts
4429
4496
  function getClientConfigFilePath(customPath) {
4430
4497
  return customPath ?? getStoreFilePath(getDefaultStorageDir(), "client");
4431
4498
  }
@@ -4436,8 +4503,7 @@ async function loadClientConfig(options) {
4436
4503
  if (raw === null) return {};
4437
4504
  return parseClientConfig(parseStore(raw));
4438
4505
  }
4439
- //#endregion
4440
- //#region ../../core/client/types.ts
4506
+ // ../../core/client/types.ts
4441
4507
  function isEnterpriseManagedAuthEnabled(config) {
4442
4508
  const ema = config.enterpriseManagedAuth;
4443
4509
  if (!ema?.idp) return false;
@@ -4454,8 +4520,7 @@ function getActiveCimdClientMetadataUrl(config) {
4454
4520
  if (!isCimdEnabled(config)) return void 0;
4455
4521
  return config.cimd?.clientMetadataUrl?.trim() || void 0;
4456
4522
  }
4457
- //#endregion
4458
- //#region ../../core/client/runner.ts
4523
+ // ../../core/client/runner.ts
4459
4524
  async function loadRunnerClientConfig(options) {
4460
4525
  return loadClientConfig({
4461
4526
  filePath: options?.clientConfigPath?.trim() || process.env.MCP_CLIENT_CONFIG_PATH?.trim() || void 0,
@@ -4498,8 +4563,7 @@ function buildRunnerClientAuthOptions(clientConfig, savedSettings, cliOverrides)
4498
4563
  ...oauth && { directAuthRecovery: true }
4499
4564
  };
4500
4565
  }
4501
- //#endregion
4502
- //#region ../../core/node/version.ts
4566
+ // ../../core/node/version.ts
4503
4567
  const ROOT_PACKAGE_NAME = "@modelcontextprotocol/inspector";
4504
4568
  function readInspectorVersion(callerUrl) {
4505
4569
  const startDir = dirname$1(fileURLToPath$1(callerUrl));
@@ -4516,8 +4580,7 @@ function readInspectorVersion(callerUrl) {
4516
4580
  }
4517
4581
  throw new Error(`Could not locate the ${ROOT_PACKAGE_NAME} root package.json above ${startDir}`);
4518
4582
  }
4519
- //#endregion
4520
- //#region ../../core/node/hostUrl.ts
4583
+ // ../../core/node/hostUrl.ts
4521
4584
  function stripBrackets(host) {
4522
4585
  return host.replace(/^\[(.*)\]$/, "$1");
4523
4586
  }
@@ -4545,8 +4608,7 @@ function isLoopbackHost(host) {
4545
4608
  const h = canonicalUrlHost(host).replace(/\.$/, "");
4546
4609
  return h === "localhost" || h === "[::1]" || /^127(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/.test(h);
4547
4610
  }
4548
- //#endregion
4549
- //#region ../../core/auth/node/runner-oauth-callback.ts
4611
+ // ../../core/auth/node/runner-oauth-callback.ts
4550
4612
  const RUNNER_OAUTH_CALLBACK_DEFAULT_HOSTNAME = "127.0.0.1";
4551
4613
  const RUNNER_OAUTH_CALLBACK_DEFAULT_PORT = 6276;
4552
4614
  const RUNNER_OAUTH_CALLBACK_PATH = "/oauth/callback";
@@ -4590,8 +4652,7 @@ function parseRunnerOAuthCallbackUrl(cliCallbackUrl) {
4590
4652
  function formatRunnerOAuthRedirectUrl(config) {
4591
4653
  return `http://${formatHostForUrl(config.hostname)}:${config.port}${config.pathname}`;
4592
4654
  }
4593
- //#endregion
4594
- //#region ../../core/json/xMcpHeader.ts
4655
+ // ../../core/json/xMcpHeader.ts
4595
4656
  const X_MCP_HEADER_KEY = "x-mcp-header";
4596
4657
  const MCP_PARAM_HEADER_PREFIX = "Mcp-Param-";
4597
4658
  const RFC9110_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
@@ -4739,8 +4800,7 @@ function mcpParamHeadersForTool(tool, args) {
4739
4800
  if (!scan.valid || scan.declarations.length === 0) return {};
4740
4801
  return buildMcpParamHeaders(scan.declarations, args);
4741
4802
  }
4742
- //#endregion
4743
- //#region ../../core/mcp/subscriptionAck.ts
4803
+ // ../../core/mcp/subscriptionAck.ts
4744
4804
  const NEVER_ACKNOWLEDGED_SDK_MESSAGE = "closed the subscription gracefully before acknowledging";
4745
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.";
4746
4806
  function isNeverAcknowledgedSubscriptionClose(error) {
@@ -4750,8 +4810,7 @@ function subscriptionFailureMessage(error) {
4750
4810
  if (isNeverAcknowledgedSubscriptionClose(error)) return NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE;
4751
4811
  return error instanceof Error ? error.message : String(error);
4752
4812
  }
4753
- //#endregion
4754
- //#region ../../core/mcp/subscriptionRefusal.ts
4813
+ // ../../core/mcp/subscriptionRefusal.ts
4755
4814
  const REFUSAL_STATUSES = /* @__PURE__ */ new Set([
4756
4815
  400,
4757
4816
  403,
@@ -4768,8 +4827,7 @@ function subscriptionListenRefusal(error) {
4768
4827
  function subscriptionListenRefusalMessage(refusal) {
4769
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.`;
4770
4829
  }
4771
- //#endregion
4772
- //#region ../../core/mcp/messageTrackingTransport.ts
4830
+ // ../../core/mcp/messageTrackingTransport.ts
4773
4831
  var MessageTrackingTransport = class {
4774
4832
  baseTransport;
4775
4833
  callbacks;
@@ -4842,8 +4900,7 @@ var MessageTrackingTransport = class {
4842
4900
  return this.negotiatedProtocolVersion;
4843
4901
  }
4844
4902
  };
4845
- //#endregion
4846
- //#region ../../core/extension/tasks/errors.ts
4903
+ // ../../core/extension/tasks/errors.ts
4847
4904
  function abortError(signal) {
4848
4905
  return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
4849
4906
  }
@@ -4857,14 +4914,12 @@ function toProtocolError(reason) {
4857
4914
  const normalized = unwrapTaskDispatchError(reason);
4858
4915
  return normalized instanceof ProtocolError ? normalized : new ProtocolError(ProtocolErrorCode.InternalError, normalized instanceof Error ? normalized.message : String(normalized));
4859
4916
  }
4860
- //#endregion
4861
- //#region ../../core/extension/tasks/notificationSchemas.ts
4917
+ // ../../core/extension/tasks/notificationSchemas.ts
4862
4918
  const TasksListChangedNotificationSchema = NotificationSchema.extend({
4863
4919
  method: z.literal("notifications/tasks/list_changed"),
4864
4920
  params: z.record(z.string(), z.unknown()).optional()
4865
4921
  });
4866
- //#endregion
4867
- //#region ../../core/extension/tasks/progress.ts
4922
+ // ../../core/extension/tasks/progress.ts
4868
4923
  var TaskProgressRouter = class {
4869
4924
  taskIds = /* @__PURE__ */ new Map();
4870
4925
  owners = /* @__PURE__ */ new Map();
@@ -4895,8 +4950,7 @@ var TaskProgressRouter = class {
4895
4950
  this.owners.clear();
4896
4951
  }
4897
4952
  };
4898
- //#endregion
4899
- //#region ../../core/extension/tasks/rawWireChannel.ts
4953
+ // ../../core/extension/tasks/rawWireChannel.ts
4900
4954
  const RAW_WIRE_ID_PREFIX = "inspector-ext-";
4901
4955
  var RawWireChannel = class {
4902
4956
  pending = /* @__PURE__ */ new Map();
@@ -5025,8 +5079,7 @@ var RawWireChannel = class {
5025
5079
  }
5026
5080
  }
5027
5081
  };
5028
- //#endregion
5029
- //#region ../../core/extension/tasks/session.ts
5082
+ // ../../core/extension/tasks/session.ts
5030
5083
  function taskSessionEndpointId(config, clientInfo) {
5031
5084
  return createTaskSessionEndpointId("inspector", config.type === "sse" || config.type === "streamable-http" ? {
5032
5085
  host: clientInfo,
@@ -5049,8 +5102,7 @@ function isTasksExtensionNegotiated(era, capabilities) {
5049
5102
  const extension = capabilities?.extensions?.[TASKS_EXTENSION_KEY];
5050
5103
  return extension !== null && typeof extension === "object" && !Array.isArray(extension) && Object.keys(extension).length === 0;
5051
5104
  }
5052
- //#endregion
5053
- //#region ../../core/extension/tasks/wire.ts
5105
+ // ../../core/extension/tasks/wire.ts
5054
5106
  const taskToolResultCodec = runtimeCodecFromStandardSchema({ "~standard": {
5055
5107
  version: 1,
5056
5108
  vendor: "mcp-inspector",
@@ -5087,8 +5139,7 @@ function taskInputOrigin(delivery) {
5087
5139
  if (delivery === "request-retry") return "input-required";
5088
5140
  return "server-request";
5089
5141
  }
5090
- //#endregion
5091
- //#region ../../core/mcp/extensions.ts
5142
+ // ../../core/mcp/extensions.ts
5092
5143
  const EMA_EXTENSION_KEY = "io.modelcontextprotocol/enterprise-managed-authorization";
5093
5144
  const UI_EXTENSION_KEY = "io.modelcontextprotocol/ui";
5094
5145
  const MCP_APP_MIME_TYPE = RESOURCE_MIME_TYPE;
@@ -5125,8 +5176,7 @@ function buildClientExtensions(input) {
5125
5176
  if (input.enterpriseManaged) map[EMA_EXTENSION_KEY] = {};
5126
5177
  return map;
5127
5178
  }
5128
- //#endregion
5129
- //#region ../../core/mcp/appElicitation.ts
5179
+ // ../../core/mcp/appElicitation.ts
5130
5180
  function uiExtension(capabilities) {
5131
5181
  const ext = capabilities?.extensions?.[UI_EXTENSION_KEY];
5132
5182
  return typeof ext === "object" && ext !== null ? ext : void 0;
@@ -5181,8 +5231,7 @@ function validateAppElicitResult(provider, params, result) {
5181
5231
  return;
5182
5232
  }
5183
5233
  }
5184
- //#endregion
5185
- //#region ../../core/mcp/toolOutputValidation.ts
5234
+ // ../../core/mcp/toolOutputValidation.ts
5186
5235
  function validateToolOutput(provider, tool, result) {
5187
5236
  if (!tool.outputSchema) return void 0;
5188
5237
  const structured = result.structuredContent;
@@ -5194,8 +5243,7 @@ function validateToolOutput(provider, tool, result) {
5194
5243
  return;
5195
5244
  }
5196
5245
  }
5197
- //#endregion
5198
- //#region ../../core/json/linearRegExp.ts
5246
+ // ../../core/json/linearRegExp.ts
5199
5247
  var CharMatcher = class {
5200
5248
  re;
5201
5249
  ascii = /* @__PURE__ */ new Uint8Array(128);
@@ -5690,8 +5738,7 @@ function compileLinearRegExp(pattern, unicode, budget) {
5690
5738
  };
5691
5739
  }
5692
5740
  }
5693
- //#endregion
5694
- //#region ../../core/mcp/linearPatternValidator.ts
5741
+ // ../../core/mcp/linearPatternValidator.ts
5695
5742
  const PATTERN_EVALUATION_BUDGET = 2e7;
5696
5743
  const SCHEMA_COMPILE_BUDGET = {
5697
5744
  steps: 10 * MAX_COMPILE_STEPS,
@@ -5915,8 +5962,7 @@ function stripExecution(tool) {
5915
5962
  function eraToolItemSchema(wire, normalize) {
5916
5963
  return wire.transform((parsed) => normalize(parsed));
5917
5964
  }
5918
- //#endregion
5919
- //#region ../../core/mcp/uriTemplate.ts
5965
+ // ../../core/mcp/uriTemplate.ts
5920
5966
  const OPERATORS = [
5921
5967
  "+",
5922
5968
  "#",
@@ -6141,8 +6187,7 @@ function valueLengthError(values, names) {
6141
6187
  function declaredNames(parts) {
6142
6188
  return [...new Set(parts.flatMap((part) => part.kind === "expression" ? part.names : []))];
6143
6189
  }
6144
- //#endregion
6145
- //#region ../../core/mcp/typedEventTarget.ts
6190
+ // ../../core/mcp/typedEventTarget.ts
6146
6191
  var TypedEventGeneric = class extends CustomEvent {
6147
6192
  constructor(type, detail) {
6148
6193
  super(type, { detail });
@@ -6168,11 +6213,9 @@ var TypedEventTarget = class extends EventTarget {
6168
6213
  super.removeEventListener(type, listener, options);
6169
6214
  }
6170
6215
  };
6171
- //#endregion
6172
- //#region ../../core/mcp/inspectorClientEventTarget.ts
6216
+ // ../../core/mcp/inspectorClientEventTarget.ts
6173
6217
  var InspectorClientEventTarget = class extends TypedEventTarget {};
6174
- //#endregion
6175
- //#region ../../core/mcp/samplingCreateMessage.ts
6218
+ // ../../core/mcp/samplingCreateMessage.ts
6176
6219
  var SamplingCreateMessage = class {
6177
6220
  id;
6178
6221
  timestamp;
@@ -6216,8 +6259,7 @@ var SamplingCreateMessage = class {
6216
6259
  this.onRemove(this.id);
6217
6260
  }
6218
6261
  };
6219
- //#endregion
6220
- //#region ../../core/mcp/elicitationCreateMessage.ts
6262
+ // ../../core/mcp/elicitationCreateMessage.ts
6221
6263
  var ElicitationCreateMessage = class {
6222
6264
  id;
6223
6265
  timestamp;
@@ -6264,8 +6306,7 @@ var ElicitationCreateMessage = class {
6264
6306
  this.onRemove(this.id);
6265
6307
  }
6266
6308
  };
6267
- //#endregion
6268
- //#region ../../core/mcp/urlElicitation.ts
6309
+ // ../../core/mcp/urlElicitation.ts
6269
6310
  var UrlElicitationLoopError = class extends Error {
6270
6311
  url;
6271
6312
  constructor(url) {
@@ -6279,8 +6320,7 @@ function getUrlElicitationsFromError(error) {
6279
6320
  if (error instanceof ProtocolError && error.code === ProtocolErrorCode.UrlElicitationRequired) return error.data?.elicitations ?? [];
6280
6321
  return null;
6281
6322
  }
6282
- //#endregion
6283
- //#region ../../core/mcp/toolCallCancelledError.ts
6323
+ // ../../core/mcp/toolCallCancelledError.ts
6284
6324
  var ToolCallCancelledError = class extends Error {
6285
6325
  toolName;
6286
6326
  constructor(toolName) {
@@ -6289,8 +6329,7 @@ var ToolCallCancelledError = class extends Error {
6289
6329
  this.toolName = toolName;
6290
6330
  }
6291
6331
  };
6292
- //#endregion
6293
- //#region ../../core/auth/endpointOverrides.ts
6332
+ // ../../core/auth/endpointOverrides.ts
6294
6333
  const OVERRIDE_FIELDS = {
6295
6334
  authorizationUrl: "authorization_endpoint",
6296
6335
  tokenUrl: "token_endpoint"
@@ -6467,8 +6506,7 @@ function withOAuthEndpointOverrides(fetchFn, getOverrides) {
6467
6506
  return responseWithBody(response, JSON.stringify(applyOAuthEndpointOverrides(parsed, overrides)));
6468
6507
  };
6469
6508
  }
6470
- //#endregion
6471
- //#region ../../core/auth/oidcDiscoveryCompat.ts
6509
+ // ../../core/auth/oidcDiscoveryCompat.ts
6472
6510
  const RFC8414_WELL_KNOWN = "/.well-known/oauth-authorization-server";
6473
6511
  const OIDC_WELL_KNOWN$1 = "/.well-known/openid-configuration";
6474
6512
  const COMPAT_SOURCE_HEADER = "x-inspector-oauth-metadata-source";
@@ -6590,8 +6628,7 @@ function withRfc8414OidcCompat(fetchFn) {
6590
6628
  return response;
6591
6629
  };
6592
6630
  }
6593
- //#endregion
6594
- //#region ../../core/logging/logger.ts
6631
+ // ../../core/logging/logger.ts
6595
6632
  const noop = () => {};
6596
6633
  function createSilentLogger() {
6597
6634
  const logger = {
@@ -6608,8 +6645,7 @@ function createSilentLogger() {
6608
6645
  return logger;
6609
6646
  }
6610
6647
  const silentLogger = createSilentLogger();
6611
- //#endregion
6612
- //#region ../../core/mcp/connectionDiagnostics.ts
6648
+ // ../../core/mcp/connectionDiagnostics.ts
6613
6649
  function isRequestTimeoutData(value) {
6614
6650
  return typeof value === "object" && value !== null && typeof value.timeout === "number";
6615
6651
  }
@@ -6631,7 +6667,7 @@ function httpStatusTextOf(err) {
6631
6667
  if (typeof err !== "object" || err === null || !("statusText" in err)) return;
6632
6668
  return typeof err.statusText === "string" ? err.statusText : void 0;
6633
6669
  }
6634
- function formatDuration(ms) {
6670
+ function formatDuration$1(ms) {
6635
6671
  const clamped = Math.max(0, ms);
6636
6672
  if (clamped < 1e3) return `${Math.round(clamped)}ms`;
6637
6673
  const totalSeconds = Math.round(clamped / 1e3);
@@ -6654,7 +6690,7 @@ function plural(count, noun) {
6654
6690
  }
6655
6691
  function describeOutstanding(requests, now) {
6656
6692
  if (requests.length === 0) return "No requests are unanswered.";
6657
- 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)`);
6658
6694
  const rest = requests.length - listed.length;
6659
6695
  const tail = rest > 0 ? `, and ${rest} more` : "";
6660
6696
  const verb = requests.length === 1 ? "is" : "are";
@@ -6662,14 +6698,14 @@ function describeOutstanding(requests, now) {
6662
6698
  }
6663
6699
  function describeLastResponse(lastResponse, now) {
6664
6700
  if (!lastResponse) return "No response has been received this session.";
6665
- return `Last response received ${formatDuration(now - lastResponse.receivedAt)} ago (${lastResponse.method}).`;
6701
+ return `Last response received ${formatDuration$1(now - lastResponse.receivedAt)} ago (${lastResponse.method}).`;
6666
6702
  }
6667
6703
  function describeStream(stream, now) {
6668
6704
  if (!stream) return void 0;
6669
6705
  const endpoint = describeStreamEndpoint(stream.url);
6670
6706
  const events = plural(stream.eventCount, "event");
6671
- if (stream.closedAt !== void 0) return `Notification stream (${endpoint}) closed ${formatDuration(now - stream.closedAt)} ago after ${formatDuration(stream.closedAt - stream.openedAt)}, ${events} delivered.`;
6672
- 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.`;
6673
6709
  }
6674
6710
  function describeConnectionDiagnostics(diagnostics) {
6675
6711
  const now = diagnostics.capturedAt;
@@ -6686,7 +6722,7 @@ function annotateRequestTimeout(err, method, diagnostics) {
6686
6722
  method,
6687
6723
  diagnostics
6688
6724
  };
6689
- 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)}`;
6690
6726
  const annotated = new SdkError(SdkErrorCode.RequestTimeout, message, data);
6691
6727
  annotated.cause = err;
6692
6728
  return annotated;
@@ -6756,7 +6792,7 @@ function attachRetryAfter(err, retryAfter) {
6756
6792
  err.data.retryAfter = retryAfter;
6757
6793
  }
6758
6794
  function describeRetry(retryAfter, retryAfterMs) {
6759
- 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)}.`;
6760
6796
  if (retryAfter !== void 0) return `The server sent an unparseable Retry-After (${retryAfter}).`;
6761
6797
  return "The server sent no Retry-After header.";
6762
6798
  }
@@ -6801,8 +6837,7 @@ function applyAuthorizationParams(authorizationUrl, params) {
6801
6837
  for (const [key, value] of applicable) merged.searchParams.set(key.trim(), value);
6802
6838
  return merged;
6803
6839
  }
6804
- //#endregion
6805
- //#region ../../core/auth/scopes.ts
6840
+ // ../../core/auth/scopes.ts
6806
6841
  const computeScopeUnion$1 = computeScopeUnion;
6807
6842
  const isStrictScopeSuperset$1 = isStrictScopeSuperset;
6808
6843
  const OFFLINE_ACCESS_SCOPE = "offline_access";
@@ -6830,8 +6865,7 @@ function resolveEffectiveGrantedScope(storedScope, tokenScope) {
6830
6865
  if (granted) return granted;
6831
6866
  return computeScopeUnion$1(storedScope, tokenScope);
6832
6867
  }
6833
- //#endregion
6834
- //#region ../../core/auth/providers.ts
6868
+ // ../../core/auth/providers.ts
6835
6869
  var MutableRedirectUrlProvider = class {
6836
6870
  redirectUrl = "";
6837
6871
  getRedirectUrl() {
@@ -7062,8 +7096,7 @@ var BaseOAuthClientProvider = class {
7062
7096
  }
7063
7097
  }
7064
7098
  };
7065
- //#endregion
7066
- //#region ../../core/auth/types.ts
7099
+ // ../../core/auth/types.ts
7067
7100
  function authProtocolFromEnterpriseManaged(enterpriseManaged) {
7068
7101
  return enterpriseManaged ? "ema" : "standard";
7069
7102
  }
@@ -7084,8 +7117,7 @@ const EMPTY_OAUTH_FLOW_STATE = {
7084
7117
  statusMessage: null,
7085
7118
  validationError: null
7086
7119
  };
7087
- //#endregion
7088
- //#region ../../core/auth/mcpAuth.ts
7120
+ // ../../core/auth/mcpAuth.ts
7089
7121
  async function mcpAuth(provider, options) {
7090
7122
  if (options.forceReauthorization && options.authorizationCode !== void 0) throw new Error("forceReauthorization cannot be combined with authorizationCode");
7091
7123
  return auth(provider, {
@@ -7356,8 +7388,7 @@ async function runPlan(plan, params) {
7356
7388
  }
7357
7389
  return aggregateOutcomes(outcomes);
7358
7390
  }
7359
- //#endregion
7360
- //#region ../../core/auth/ema/clientConfigError.ts
7391
+ // ../../core/auth/ema/clientConfigError.ts
7361
7392
  function emaClientNotConfiguredMessage(reason) {
7362
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.";
7363
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.";
@@ -7373,12 +7404,10 @@ var EmaClientNotConfiguredError = class extends Error {
7373
7404
  function isEmaClientNotConfiguredError(err) {
7374
7405
  return err instanceof EmaClientNotConfiguredError;
7375
7406
  }
7376
- //#endregion
7377
- //#region ../../core/auth/ema/constants.ts
7407
+ // ../../core/auth/ema/constants.ts
7378
7408
  const GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";
7379
7409
  const IDP_OIDC_SCOPES = "openid offline_access";
7380
- //#endregion
7381
- //#region ../../core/auth/ema/jwt.ts
7410
+ // ../../core/auth/ema/jwt.ts
7382
7411
  function decodeBase64Url(segment) {
7383
7412
  const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
7384
7413
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
@@ -7405,8 +7434,19 @@ function isJwtFormat(token) {
7405
7434
  const parts = token.split(".");
7406
7435
  return parts.length === 3 && parts[0].length > 0 && parts[1].length > 0 && parts[2] !== void 0;
7407
7436
  }
7408
- //#endregion
7409
- //#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
7410
7450
  function normalizeIdpIssuer(issuer) {
7411
7451
  return issuer.replace(/\/$/, "");
7412
7452
  }
@@ -7414,8 +7454,7 @@ const IDP_OAUTH_KEY_PREFIX = "ema-idp:";
7414
7454
  function idpOAuthStorageKey(issuer) {
7415
7455
  return `${IDP_OAUTH_KEY_PREFIX}${normalizeIdpIssuer(issuer)}`;
7416
7456
  }
7417
- //#endregion
7418
- //#region ../../core/auth/ema/tokenEndpoint.ts
7457
+ // ../../core/auth/ema/tokenEndpoint.ts
7419
7458
  async function parseOAuthTokenErrorResponse(response, step) {
7420
7459
  let body;
7421
7460
  try {
@@ -7459,8 +7498,7 @@ async function postOAuthTokenRequest(tokenUrl, body, metadata, clientInformation
7459
7498
  body
7460
7499
  });
7461
7500
  }
7462
- //#endregion
7463
- //#region ../../core/auth/ema/idpOidc.ts
7501
+ // ../../core/auth/ema/idpOidc.ts
7464
7502
  function idpClientInformation(idp) {
7465
7503
  return {
7466
7504
  client_id: idp.clientId,
@@ -7583,8 +7621,7 @@ async function getValidIdToken(params) {
7583
7621
  return;
7584
7622
  }
7585
7623
  }
7586
- //#endregion
7587
- //#region ../../core/auth/discovery.ts
7624
+ // ../../core/auth/discovery.ts
7588
7625
  function serverUrlAsAuthorizationServer(serverUrl) {
7589
7626
  try {
7590
7627
  const url = new URL(serverUrl);
@@ -7626,8 +7663,7 @@ async function discoverAuthorizationServerMetadataFromCandidates(candidates, dis
7626
7663
  async function discoverAuthorizationServerMetadataForServer(serverUrl, resourceMetadata, fetchFn) {
7627
7664
  return (await discoverAuthorizationServerMetadataFromCandidates(getAuthorizationServerUrlCandidates(serverUrl, resourceMetadata), (candidate) => discoverAuthorizationServerMetadata(candidate, { fetchFn })))?.metadata;
7628
7665
  }
7629
- //#endregion
7630
- //#region ../../core/auth/ema/resourceContext.ts
7666
+ // ../../core/auth/ema/resourceContext.ts
7631
7667
  function resolveEmaScopes(resourceMetadata, configuredScope) {
7632
7668
  const trimmed = configuredScope?.trim();
7633
7669
  if (trimmed) return trimmed;
@@ -7660,8 +7696,7 @@ async function discoverResourceAsMetadata(resourceAsUrl, fetchFn) {
7660
7696
  if (!metadata) throw new Error("Failed to discover resource authorization server metadata");
7661
7697
  return metadata;
7662
7698
  }
7663
- //#endregion
7664
- //#region ../../core/auth/ema/wire.ts
7699
+ // ../../core/auth/ema/wire.ts
7665
7700
  async function exchangeIdJag(params) {
7666
7701
  const issuer = normalizeIdpIssuer(params.idp.issuer);
7667
7702
  const resource = params.resource.trim();
@@ -7705,8 +7740,7 @@ async function redeemIdJagForAccessToken(params) {
7705
7740
  if (!response.ok) throw await parseOAuthTokenErrorResponse(response, "EMA leg 3 (resource AS JWT bearer grant)");
7706
7741
  return OAuthTokensSchema.parse(await response.json());
7707
7742
  }
7708
- //#endregion
7709
- //#region ../../core/auth/ema/emaFlow.ts
7743
+ // ../../core/auth/ema/emaFlow.ts
7710
7744
  function wrapEmaMintError(err) {
7711
7745
  const message = err instanceof Error ? err.message : String(err);
7712
7746
  return new Error(`EMA legs 2–3 (resource token mint): ${message}`, { cause: err });
@@ -7806,8 +7840,7 @@ async function refreshEmaResourceTokens(config) {
7806
7840
  await saveMintedTokens(config, minted);
7807
7841
  return minted.tokens;
7808
7842
  }
7809
- //#endregion
7810
- //#region ../../core/auth/ema/idpSession.ts
7843
+ // ../../core/auth/ema/idpSession.ts
7811
7844
  async function getEmaIdpLoginState(storage, issuer) {
7812
7845
  const normalized = normalizeIdpIssuer(issuer);
7813
7846
  if (!normalized) return "none";
@@ -7817,8 +7850,7 @@ async function getEmaIdpLoginState(storage, issuer) {
7817
7850
  if (session.refreshToken) return "logged_in";
7818
7851
  return "expired";
7819
7852
  }
7820
- //#endregion
7821
- //#region ../../core/auth/connection-state.ts
7853
+ // ../../core/auth/connection-state.ts
7822
7854
  function isAccessTokenUsable$1(tokens) {
7823
7855
  if (!tokens?.access_token) return false;
7824
7856
  return !isJwtExpired(tokens.access_token);
@@ -7901,8 +7933,7 @@ async function hasPersistedOAuthServerState(storage, serverUrl) {
7901
7933
  function protocolFromOAuthConfig(config) {
7902
7934
  return authProtocolFromEnterpriseManaged(config.enterpriseManaged);
7903
7935
  }
7904
- //#endregion
7905
- //#region ../../core/auth/cimd.ts
7936
+ // ../../core/auth/cimd.ts
7906
7937
  async function ensureCimdClientRegistration(params) {
7907
7938
  const clientMetadataUrl = params.provider.clientMetadataUrl?.trim();
7908
7939
  if (!clientMetadataUrl) return;
@@ -7928,8 +7959,7 @@ async function ensureCimdClientRegistration(params) {
7928
7959
  ...issuer && { issuer }
7929
7960
  });
7930
7961
  }
7931
- //#endregion
7932
- //#region ../../core/auth/ema/transportProvider.ts
7962
+ // ../../core/auth/ema/transportProvider.ts
7933
7963
  function isAccessTokenUsable(tokens, skewMs = 6e4) {
7934
7964
  if (!tokens.access_token) return false;
7935
7965
  return !isJwtExpired(tokens.access_token, skewMs);
@@ -7989,8 +8019,7 @@ var EmaTransportOAuthProvider = class {
7989
8019
  return this.inner.codeVerifier();
7990
8020
  }
7991
8021
  };
7992
- //#endregion
7993
- //#region ../../core/auth/oauthUx.ts
8022
+ // ../../core/auth/oauthUx.ts
7994
8023
  function isStandardOAuthStepUp(challenge, options) {
7995
8024
  return challenge.reason === "insufficient_scope" && !options?.enterpriseManaged;
7996
8025
  }
@@ -8062,8 +8091,7 @@ function issuerBindingFailureCopy(failure, options) {
8062
8091
  })
8063
8092
  };
8064
8093
  }
8065
- //#endregion
8066
- //#region ../../core/mcp/oauthManager.ts
8094
+ // ../../core/mcp/oauthManager.ts
8067
8095
  var OAuthManager = class {
8068
8096
  params;
8069
8097
  oauthConfig;
@@ -8546,8 +8574,7 @@ var OAuthManager = class {
8546
8574
  return provider;
8547
8575
  }
8548
8576
  };
8549
- //#endregion
8550
- //#region ../../core/mcp/remote/types.ts
8577
+ // ../../core/mcp/remote/types.ts
8551
8578
  function oauthTokensToRemoteAuthState(tokens) {
8552
8579
  return { oauthTokens: {
8553
8580
  access_token: tokens.access_token,
@@ -8558,8 +8585,7 @@ function oauthTokensToRemoteAuthState(tokens) {
8558
8585
  id_token: tokens.id_token
8559
8586
  } };
8560
8587
  }
8561
- //#endregion
8562
- //#region ../../core/mcp/remote/progressToken.ts
8588
+ // ../../core/mcp/remote/progressToken.ts
8563
8589
  function progressTokenOf(message) {
8564
8590
  if ("method" in message && message.method === "notifications/progress" && "params" in message && typeof message.params === "object" && message.params !== null) {
8565
8591
  const parsed = ProgressTokenSchema.safeParse(message.params.progressToken);
@@ -8572,8 +8598,7 @@ function waitForProgressToken(waits, token) {
8572
8598
  const numeric = Number(token);
8573
8599
  return Number.isSafeInteger(numeric) ? waits.get(numeric) : void 0;
8574
8600
  }
8575
- //#endregion
8576
- //#region ../../core/mcp/remote/remoteClientTransport.ts
8601
+ // ../../core/mcp/remote/remoteClientTransport.ts
8577
8602
  const DEFAULT_SSE_RESPONSE_TIMEOUT_MS = 6e4;
8578
8603
  function requestIdForMessage(message) {
8579
8604
  if ("method" in message && "id" in message && message.id !== null && message.id !== void 0) {
@@ -8717,7 +8742,8 @@ var RemoteClientTransport = class {
8717
8742
  const body = {
8718
8743
  config: this.config,
8719
8744
  ...authState && { authState },
8720
- ...this.options.settings && { settings: this.options.settings }
8745
+ ...this.options.settings && { settings: this.options.settings },
8746
+ ...this.options.serverName && { serverName: this.options.serverName }
8721
8747
  };
8722
8748
  const res = await this.fetchFn(`${this.baseUrl}/api/mcp/connect`, {
8723
8749
  method: "POST",
@@ -9003,8 +9029,25 @@ var RemoteClientTransport = class {
9003
9029
  onerror;
9004
9030
  onmessage;
9005
9031
  };
9006
- //#endregion
9007
- //#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
9008
9051
  const corePackageJson = {
9009
9052
  name: "mcp-inspector",
9010
9053
  version: "0.0.0"
@@ -9133,6 +9176,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9133
9176
  transportClientFactory;
9134
9177
  fetchFn;
9135
9178
  effectiveAuthFetch;
9179
+ fetchRefusals = [];
9136
9180
  sessionId;
9137
9181
  transportConfig;
9138
9182
  directAuthRecoveryActive = null;
@@ -9168,8 +9212,9 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9168
9212
  resources: options.listChangedNotifications?.resources ?? true,
9169
9213
  prompts: options.listChangedNotifications?.prompts ?? true
9170
9214
  };
9171
- const transportBase = this.fetchFn ?? fetch;
9172
- 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);
9173
9218
  const isMcpEndpoint = exemptMcpEndpoint(() => this.getServerUrl(), () => this.transportConfig?.type === "sse");
9174
9219
  const getOverrides = () => this.oauthManager?.getEndpointOverrides();
9175
9220
  const withOverrides = withOAuthEndpointOverrides(oauthBase ? routeOAuthRequests(transportBase, oauthBase, isMcpEndpoint) : transportBase, getOverrides);
@@ -9706,6 +9751,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9706
9751
  while (handlers?.size !== void 0 && handlers.size > 0 && Date.now() < deadline) await new Promise((r) => setTimeout(r, 10));
9707
9752
  }
9708
9753
  await this.closeTaskSessionBestEffort();
9754
+ await terminateSessionBestEffort(this.baseTransport);
9709
9755
  try {
9710
9756
  await this.client.close();
9711
9757
  } catch {}
@@ -9748,6 +9794,14 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
9748
9794
  this.dispatchTypedEvent("excludedToolsChange", this.excludedTools);
9749
9795
  this.dispatchTypedEvent("malformedListItemsChange", []);
9750
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
+ }
9751
9805
  getAppRendererClient() {
9752
9806
  if (!this.client || this.status !== "connected") return null;
9753
9807
  return this.client;
@@ -11400,8 +11454,7 @@ var InspectorClient = class InspectorClient extends InspectorClientEventTarget {
11400
11454
  return this.oauthManager.getOAuthState();
11401
11455
  }
11402
11456
  };
11403
- //#endregion
11404
- //#region ../../core/mcp/state/managedListState.ts
11457
+ // ../../core/mcp/state/managedListState.ts
11405
11458
  var ManagedListState = class extends TypedEventTarget {
11406
11459
  items = [];
11407
11460
  client = null;
@@ -11546,8 +11599,7 @@ var ManagedListState = class extends TypedEventTarget {
11546
11599
  this.loaded = false;
11547
11600
  }
11548
11601
  };
11549
- //#endregion
11550
- //#region ../../core/mcp/state/managedToolsState.ts
11602
+ // ../../core/mcp/state/managedToolsState.ts
11551
11603
  var ManagedToolsState = class extends ManagedListState {
11552
11604
  constructor(client, debounceMs = 250) {
11553
11605
  super(client, {
@@ -11570,8 +11622,7 @@ var ManagedToolsState = class extends ManagedListState {
11570
11622
  return this.getItems();
11571
11623
  }
11572
11624
  };
11573
- //#endregion
11574
- //#region ../../core/mcp/state/messageLogState.ts
11625
+ // ../../core/mcp/state/messageLogState.ts
11575
11626
  var MessageLogState = class extends TypedEventTarget {
11576
11627
  messages = [];
11577
11628
  pendingRequestEntries = /* @__PURE__ */ new Map();
@@ -11588,6 +11639,16 @@ var MessageLogState = class extends TypedEventTarget {
11588
11639
  this.dispatchTypedEvent("message", entry);
11589
11640
  this.dispatchTypedEvent("messagesChange", this.getMessages());
11590
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
+ };
11591
11652
  const onMessage = (event) => {
11592
11653
  const entry = event.detail;
11593
11654
  if (entry.direction === "request") {
@@ -11601,9 +11662,12 @@ var MessageLogState = class extends TypedEventTarget {
11601
11662
  const requestEntry = messageId !== void 0 ? this.pendingRequestEntries.get(messageId) : void 0;
11602
11663
  if (requestEntry) {
11603
11664
  this.pendingRequestEntries.delete(messageId);
11604
- requestEntry.response = entry.message;
11605
- requestEntry.duration = entry.timestamp.getTime() - requestEntry.timestamp.getTime();
11606
- 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);
11607
11671
  this.dispatchTypedEvent("messagesChange", this.getMessages());
11608
11672
  return;
11609
11673
  }
@@ -11617,8 +11681,12 @@ var MessageLogState = class extends TypedEventTarget {
11617
11681
  if (entry.message.id !== id) continue;
11618
11682
  if (entry.direction === "notification") continue;
11619
11683
  if (entry.direction === "request" && !entry.response) continue;
11620
- entry.clientError = reason;
11621
- this.dispatchTypedEvent("message", entry);
11684
+ const updated = {
11685
+ ...entry,
11686
+ clientError: reason
11687
+ };
11688
+ this.messages[i] = updated;
11689
+ this.dispatchTypedEvent("message", updated);
11622
11690
  this.dispatchTypedEvent("messagesChange", this.getMessages());
11623
11691
  return;
11624
11692
  }
@@ -11628,9 +11696,12 @@ var MessageLogState = class extends TypedEventTarget {
11628
11696
  const requestEntry = this.pendingRequestEntries.get(id);
11629
11697
  if (!requestEntry) return;
11630
11698
  this.pendingRequestEntries.delete(id);
11631
- requestEntry.clientError = reason;
11632
- requestEntry.duration = Date.now() - requestEntry.timestamp.getTime();
11633
- 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);
11634
11705
  this.dispatchTypedEvent("messagesChange", this.getMessages());
11635
11706
  };
11636
11707
  const onStatusChange = () => {
@@ -11674,8 +11745,7 @@ var MessageLogState = class extends TypedEventTarget {
11674
11745
  this.pendingRequestEntries.clear();
11675
11746
  }
11676
11747
  };
11677
- //#endregion
11678
- //#region ../../core/mcp/state/fetchRequestLogState.ts
11748
+ // ../../core/mcp/state/fetchRequestLogState.ts
11679
11749
  var FetchRequestLogState = class extends TypedEventTarget {
11680
11750
  fetchRequests = [];
11681
11751
  client = null;
@@ -11794,8 +11864,7 @@ var FetchRequestLogState = class extends TypedEventTarget {
11794
11864
  this.fetchRequests = [];
11795
11865
  }
11796
11866
  };
11797
- //#endregion
11798
- //#region ../../core/mcp/state/stderrLogState.ts
11867
+ // ../../core/mcp/state/stderrLogState.ts
11799
11868
  var StderrLogState = class extends TypedEventTarget {
11800
11869
  stderrLogs = [];
11801
11870
  client = null;
@@ -11832,8 +11901,7 @@ var StderrLogState = class extends TypedEventTarget {
11832
11901
  this.stderrLogs = [];
11833
11902
  }
11834
11903
  };
11835
- //#endregion
11836
- //#region ../../core/mcp/state/managedResourcesState.ts
11904
+ // ../../core/mcp/state/managedResourcesState.ts
11837
11905
  var ManagedResourcesState = class extends ManagedListState {
11838
11906
  constructor(client, debounceMs = 250) {
11839
11907
  super(client, {
@@ -11856,8 +11924,7 @@ var ManagedResourcesState = class extends ManagedListState {
11856
11924
  return this.getItems();
11857
11925
  }
11858
11926
  };
11859
- //#endregion
11860
- //#region ../../core/mcp/state/managedResourceTemplatesState.ts
11927
+ // ../../core/mcp/state/managedResourceTemplatesState.ts
11861
11928
  var ManagedResourceTemplatesState = class extends ManagedListState {
11862
11929
  constructor(client, debounceMs = 250) {
11863
11930
  super(client, {
@@ -11880,8 +11947,7 @@ var ManagedResourceTemplatesState = class extends ManagedListState {
11880
11947
  return this.getItems();
11881
11948
  }
11882
11949
  };
11883
- //#endregion
11884
- //#region ../../core/mcp/state/managedPromptsState.ts
11950
+ // ../../core/mcp/state/managedPromptsState.ts
11885
11951
  var ManagedPromptsState = class extends ManagedListState {
11886
11952
  constructor(client, debounceMs = 250) {
11887
11953
  super(client, {
@@ -11904,8 +11970,7 @@ var ManagedPromptsState = class extends ManagedListState {
11904
11970
  return this.getItems();
11905
11971
  }
11906
11972
  };
11907
- //#endregion
11908
- //#region ../../core/mcp/state/mergeTaskIntoList.ts
11973
+ // ../../core/mcp/state/mergeTaskIntoList.ts
11909
11974
  function mergeTaskIntoList(tasks, taskId, task) {
11910
11975
  const normalized = {
11911
11976
  ...task,
@@ -11918,8 +11983,7 @@ function mergeTaskIntoList(tasks, taskId, task) {
11918
11983
  next[idx] = normalized;
11919
11984
  return next;
11920
11985
  }
11921
- //#endregion
11922
- //#region ../../core/mcp/state/managedRequestorTasksState.ts
11986
+ // ../../core/mcp/state/managedRequestorTasksState.ts
11923
11987
  const MAX_PAGES = 100;
11924
11988
  const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
11925
11989
  "completed",
@@ -12054,8 +12118,7 @@ var ManagedRequestorTasksState = class extends TypedEventTarget {
12054
12118
  this.cancelledTaskIds.clear();
12055
12119
  }
12056
12120
  };
12057
- //#endregion
12058
- //#region ../../core/mcp/state/resourceSubscriptionsState.ts
12121
+ // ../../core/mcp/state/resourceSubscriptionsState.ts
12059
12122
  var ResourceSubscriptionsState = class extends TypedEventTarget {
12060
12123
  subscribedUris = [];
12061
12124
  lastUpdatedByUri = /* @__PURE__ */ new Map();
@@ -12144,8 +12207,7 @@ var ResourceSubscriptionsState = class extends TypedEventTarget {
12144
12207
  this.streamState = INACTIVE_SUBSCRIPTION_STREAM_STATE;
12145
12208
  }
12146
12209
  };
12147
- //#endregion
12148
- //#region ../../core/mcp/state/managedSkillsState.ts
12210
+ // ../../core/mcp/state/managedSkillsState.ts
12149
12211
  const REPEATED_CURSOR_MESSAGE = "Server repeated a pagination cursor in skills/list; stopped to avoid an infinite walk.";
12150
12212
  const SKILLS_MAX_PAGES = 64;
12151
12213
  const SKILLS_PAGE_LIMIT_MESSAGE = `skills/list exceeded ${SKILLS_MAX_PAGES} pages without the server's pagination converging`;
@@ -12254,17 +12316,45 @@ var ManagedSkillsState = class extends TypedEventTarget {
12254
12316
  this.error = null;
12255
12317
  }
12256
12318
  };
12257
- //#endregion
12258
- //#region ../../core/react/useStoreSnapshot.ts
12259
- 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) {
12260
12338
  const cache = useRef(null);
12261
12339
  const subscribe = useCallback((onStoreChange) => {
12262
12340
  if (!store) return () => {};
12263
- 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);
12264
12349
  return () => {
12265
- store.removeEventListener(event, onStoreChange);
12350
+ store.removeEventListener(event, notify);
12351
+ cancel();
12266
12352
  };
12267
- }, [store, event]);
12353
+ }, [
12354
+ store,
12355
+ event,
12356
+ schedule
12357
+ ]);
12268
12358
  const getSnapshot = useCallback(() => {
12269
12359
  const revision = store ? store.getEventRevision(event) : 0;
12270
12360
  const cached = cache.current;
@@ -12287,8 +12377,7 @@ function useStoreSnapshot(store, event, read, whenAbsent) {
12287
12377
  ]);
12288
12378
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
12289
12379
  }
12290
- //#endregion
12291
- //#region ../../core/react/useInspectorClient.ts
12380
+ // ../../core/react/useInspectorClient.ts
12292
12381
  const EMPTY_CLIENT_CAPABILITIES = Object.freeze({});
12293
12382
  const NO_EXCLUDED_TOOLS = [];
12294
12383
  const NO_MALFORMED_LIST_ITEMS = [];
@@ -12306,7 +12395,7 @@ const readDiscoverResult = (client) => client.getDiscoverResult();
12306
12395
  const readExcludedTools = (client) => client.getExcludedTools();
12307
12396
  const readMalformedListItems = (client) => client.getMalformedListItems();
12308
12397
  const readConnectionDiagnostics = (client) => client.getConnectionDiagnostics?.() ?? NO_CONNECTION_DIAGNOSTICS;
12309
- function useInspectorClient(inspectorClient) {
12398
+ function useInspectorClient(inspectorClient, diagnosticsSchedule) {
12310
12399
  const status = useStoreSnapshot(inspectorClient, "statusChange", readStatus, "disconnected");
12311
12400
  const capabilities = useStoreSnapshot(inspectorClient, "capabilitiesChange", readCapabilities, void 0);
12312
12401
  const serverInfo = useStoreSnapshot(inspectorClient, "serverInfoChange", readServerInfo, void 0);
@@ -12316,7 +12405,7 @@ function useInspectorClient(inspectorClient) {
12316
12405
  const discoverResult = useStoreSnapshot(inspectorClient, "discoverResultChange", readDiscoverResult, void 0);
12317
12406
  const excludedTools = useStoreSnapshot(inspectorClient, "excludedToolsChange", readExcludedTools, NO_EXCLUDED_TOOLS);
12318
12407
  const malformedListItems = useStoreSnapshot(inspectorClient, "malformedListItemsChange", readMalformedListItems, NO_MALFORMED_LIST_ITEMS);
12319
- const connectionDiagnostics = useStoreSnapshot(inspectorClient, "connectionDiagnosticsChange", readConnectionDiagnostics, NO_CONNECTION_DIAGNOSTICS);
12408
+ const connectionDiagnostics = useStoreSnapshot(inspectorClient, "connectionDiagnosticsChange", readConnectionDiagnostics, NO_CONNECTION_DIAGNOSTICS, diagnosticsSchedule);
12320
12409
  const [errorState, setErrorState] = useState({ client: inspectorClient });
12321
12410
  if (errorState.client !== inspectorClient) setErrorState({ client: inspectorClient });
12322
12411
  const lastError = errorState.client === inspectorClient ? errorState.message : void 0;
@@ -12364,8 +12453,7 @@ function useInspectorClient(inspectorClient) {
12364
12453
  disconnect
12365
12454
  };
12366
12455
  }
12367
- //#endregion
12368
- //#region ../../core/react/useListError.ts
12456
+ // ../../core/react/useListError.ts
12369
12457
  function useListError(state) {
12370
12458
  const subscribe = useCallback((onStoreChange) => {
12371
12459
  if (!state) return () => {};
@@ -12378,8 +12466,7 @@ function useListError(state) {
12378
12466
  const getSnapshot = useCallback(() => state?.getError() ?? null, [state]);
12379
12467
  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
12380
12468
  }
12381
- //#endregion
12382
- //#region ../../core/react/useManagedTools.ts
12469
+ // ../../core/react/useManagedTools.ts
12383
12470
  const NO_TOOLS = [];
12384
12471
  const readTools = (state) => state.getTools();
12385
12472
  const readListChanged$2 = (state) => state.getListChanged();
@@ -12403,8 +12490,7 @@ function useManagedTools(client, managedToolsState) {
12403
12490
  }, [managedToolsState])
12404
12491
  };
12405
12492
  }
12406
- //#endregion
12407
- //#region ../../core/mcp/toolOrder.ts
12493
+ // ../../core/mcp/toolOrder.ts
12408
12494
  const toolLabelCollator = new Intl.Collator(void 0, {
12409
12495
  sensitivity: "base",
12410
12496
  numeric: true
@@ -12415,8 +12501,7 @@ function compareToolLabels(a, b) {
12415
12501
  function compareToolsByName(a, b) {
12416
12502
  return compareToolLabels(a.name, b.name);
12417
12503
  }
12418
- //#endregion
12419
- //#region ../../core/react/useManagedResources.ts
12504
+ // ../../core/react/useManagedResources.ts
12420
12505
  const NO_RESOURCES = [];
12421
12506
  const readResources = (state) => state.getResources();
12422
12507
  const readListChanged$1 = (state) => state.getListChanged();
@@ -12440,8 +12525,7 @@ function useManagedResources(client, managedResourcesState) {
12440
12525
  }, [managedResourcesState])
12441
12526
  };
12442
12527
  }
12443
- //#endregion
12444
- //#region ../../core/react/useManagedResourceTemplates.ts
12528
+ // ../../core/react/useManagedResourceTemplates.ts
12445
12529
  const NO_RESOURCE_TEMPLATES = [];
12446
12530
  const readResourceTemplates = (state) => state.getResourceTemplates();
12447
12531
  function useManagedResourceTemplates(client, managedResourceTemplatesState) {
@@ -12454,8 +12538,7 @@ function useManagedResourceTemplates(client, managedResourceTemplatesState) {
12454
12538
  }, [client, managedResourceTemplatesState])
12455
12539
  };
12456
12540
  }
12457
- //#endregion
12458
- //#region ../../core/react/useManagedPrompts.ts
12541
+ // ../../core/react/useManagedPrompts.ts
12459
12542
  const NO_PROMPTS = [];
12460
12543
  const readPrompts = (state) => state.getPrompts();
12461
12544
  const readListChanged = (state) => state.getListChanged();
@@ -12479,8 +12562,7 @@ function useManagedPrompts(client, managedPromptsState) {
12479
12562
  }, [managedPromptsState])
12480
12563
  };
12481
12564
  }
12482
- //#endregion
12483
- //#region ../../core/react/useManagedSkills.ts
12565
+ // ../../core/react/useManagedSkills.ts
12484
12566
  const NO_SKILLS = [];
12485
12567
  const NO_SKILLS_PAGINATION = Object.freeze({ pageCount: 0 });
12486
12568
  const readSkills = (state) => state.getSkills();
@@ -12498,29 +12580,25 @@ function useManagedSkills(client, managedSkillsState) {
12498
12580
  }, [client, managedSkillsState])
12499
12581
  };
12500
12582
  }
12501
- //#endregion
12502
- //#region ../../core/react/useMessageLog.ts
12583
+ // ../../core/react/useMessageLog.ts
12503
12584
  const NO_MESSAGES = [];
12504
12585
  const readMessages = (state) => state.getMessages();
12505
- function useMessageLog(messageLogState) {
12506
- return { messages: useStoreSnapshot(messageLogState, "messagesChange", readMessages, NO_MESSAGES) };
12586
+ function useMessageLog(messageLogState, schedule) {
12587
+ return { messages: useStoreSnapshot(messageLogState, "messagesChange", readMessages, NO_MESSAGES, schedule) };
12507
12588
  }
12508
- //#endregion
12509
- //#region ../../core/react/useFetchRequestLog.ts
12589
+ // ../../core/react/useFetchRequestLog.ts
12510
12590
  const NO_FETCH_REQUESTS = [];
12511
12591
  const readFetchRequests = (state) => state.getFetchRequests();
12512
- function useFetchRequestLog(fetchRequestLogState) {
12513
- 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) };
12514
12594
  }
12515
- //#endregion
12516
- //#region ../../core/react/useStderrLog.ts
12595
+ // ../../core/react/useStderrLog.ts
12517
12596
  const NO_STDERR_LOGS = [];
12518
12597
  const readStderrLogs = (state) => state.getStderrLogs();
12519
- function useStderrLog(stderrLogState) {
12520
- 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) };
12521
12600
  }
12522
- //#endregion
12523
- //#region ../../core/react/useManagedRequestorTasks.ts
12601
+ // ../../core/react/useManagedRequestorTasks.ts
12524
12602
  const NO_TASKS = [];
12525
12603
  const readTasks = (state) => state.getTasks();
12526
12604
  function useManagedRequestorTasks(client, managedRequestorTasksState) {
@@ -12535,8 +12613,7 @@ function useManagedRequestorTasks(client, managedRequestorTasksState) {
12535
12613
  }, [managedRequestorTasksState])
12536
12614
  };
12537
12615
  }
12538
- //#endregion
12539
- //#region ../../core/react/useResourceSubscriptions.ts
12616
+ // ../../core/react/useResourceSubscriptions.ts
12540
12617
  const NO_SUBSCRIPTIONS = [];
12541
12618
  const readSubscriptions = (state) => state.getSubscriptions();
12542
12619
  const readStreamState = (state) => state.getStreamState();
@@ -12546,8 +12623,18 @@ function useResourceSubscriptions(state) {
12546
12623
  streamState: useStoreSnapshot(state, "streamStateChange", readStreamState, INACTIVE_SUBSCRIPTION_STREAM_STATE)
12547
12624
  };
12548
12625
  }
12549
- //#endregion
12550
- //#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
12551
12638
  const MISSING_DISCOVERY_STATE_PHRASE = "discoveryState was not available";
12552
12639
  function isAuthorizationServerMismatchShape(err) {
12553
12640
  if (err === null || typeof err !== "object") return false;
@@ -12587,8 +12674,7 @@ function classifyAuthorizationServerMismatch(err) {
12587
12674
  currentIssuer: err.currentIssuer
12588
12675
  };
12589
12676
  }
12590
- //#endregion
12591
- //#region ../../core/auth/oauth-storage.ts
12677
+ // ../../core/auth/oauth-storage.ts
12592
12678
  function withIssuer(value, issuer) {
12593
12679
  return issuer === void 0 ? value : {
12594
12680
  ...value,
@@ -12865,8 +12951,7 @@ var OAuthStorageBase = class {
12865
12951
  await this.persist({ servers });
12866
12952
  }
12867
12953
  };
12868
- //#endregion
12869
- //#region ../../core/auth/store.ts
12954
+ // ../../core/auth/store.ts
12870
12955
  var OAuthMemoryStore = class {
12871
12956
  servers = {};
12872
12957
  idpSessions = {};
@@ -12929,8 +13014,7 @@ var OAuthMemoryStore = class {
12929
13014
  this.idpSessions = { ...snapshot.idpSessions ?? {} };
12930
13015
  }
12931
13016
  };
12932
- //#endregion
12933
- //#region ../../core/auth/oauth-persist.ts
13017
+ // ../../core/auth/oauth-persist.ts
12934
13018
  function mergeOAuthSections(disk, snapshot, sections) {
12935
13019
  const merged = {
12936
13020
  servers: { ...disk?.servers },
@@ -12995,8 +13079,7 @@ function parseOAuthPersistBlob(raw) {
12995
13079
  function serializeOAuthPersistBlob(snapshot) {
12996
13080
  return serializeStore(snapshot);
12997
13081
  }
12998
- //#endregion
12999
- //#region ../../core/auth/node/oauth-secrets.ts
13082
+ // ../../core/auth/node/oauth-secrets.ts
13000
13083
  const PERSIST_TOKENS_ENV = "MCP_INSPECTOR_PERSIST_TOKENS";
13001
13084
  const warnedPolicyValues = /* @__PURE__ */ new Set();
13002
13085
  function getPersistTokensPolicy(env = process.env) {
@@ -13266,8 +13349,7 @@ function snapshotHasPlaintextSecrets(snapshot) {
13266
13349
  for (const session of Object.values(snapshot.idpSessions)) if (session.idToken !== void 0 || session.refreshToken !== void 0) return true;
13267
13350
  return false;
13268
13351
  }
13269
- //#endregion
13270
- //#region ../../core/auth/node/oauth-namespace-ledger.ts
13352
+ // ../../core/auth/node/oauth-namespace-ledger.ts
13271
13353
  const namespaceLedgerPath = (stateFilePath) => `${stateFilePath}.namespaces.json`;
13272
13354
  const KEYRING_LOCATION = "keyring";
13273
13355
  const FILE_LOCATION_PREFIX = "file:";
@@ -13525,8 +13607,7 @@ async function purgeSupersededNamespaces(stateFilePath, secretStore, current, ow
13525
13607
  warnLedgerFailure("update", error);
13526
13608
  }
13527
13609
  }
13528
- //#endregion
13529
- //#region ../../core/auth/node/oauth-persist-file.ts
13610
+ // ../../core/auth/node/oauth-persist-file.ts
13530
13611
  const warnedStoreFailures = /* @__PURE__ */ new Set();
13531
13612
  function warnStoreWriteFailure(error) {
13532
13613
  const reason = error instanceof Error ? error.message : String(error);
@@ -14072,8 +14153,7 @@ function createFileOAuthPersistBackend(options) {
14072
14153
  }
14073
14154
  };
14074
14155
  }
14075
- //#endregion
14076
- //#region ../../core/auth/node/storage-node.ts
14156
+ // ../../core/auth/node/storage-node.ts
14077
14157
  const DEFAULT_STATE_PATH = getStoreFilePath(getDefaultStorageDir(), "oauth");
14078
14158
  function getStateFilePath(customPath) {
14079
14159
  if (customPath) return customPath;
@@ -14104,8 +14184,7 @@ var NodeOAuthStorage = class extends OAuthStorageBase {
14104
14184
  }), shared.coordination);
14105
14185
  }
14106
14186
  };
14107
- //#endregion
14108
- //#region ../../core/auth/node/oauth-callback-server.ts
14187
+ // ../../core/auth/node/oauth-callback-server.ts
14109
14188
  const DEFAULT_HOSTNAME = "127.0.0.1";
14110
14189
  const DEFAULT_CALLBACK_PATH = "/oauth/callback";
14111
14190
  const SUCCESS_HTML = page("OAuth complete", "OAuth complete. You can close this window.");
@@ -14279,6 +14358,28 @@ function createOAuthCallbackServer() {
14279
14358
  function buildRedirectUrl(host, port, path) {
14280
14359
  return `http://${formatHostForUrl(host)}:${port}${path}`;
14281
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
+ };
14282
14383
  function toRunnerOAuthError(err) {
14283
14384
  const failure = findIssuerBindingFailure(err);
14284
14385
  if (failure) {
@@ -14343,7 +14444,7 @@ async function runRunnerInteractiveOAuth(options) {
14343
14444
  }
14344
14445
  },
14345
14446
  onError: (params) => {
14346
- flowReject(new Error(callbackErrorMessage(params)));
14447
+ flowReject(new OAuthCallbackError(params));
14347
14448
  }
14348
14449
  }));
14349
14450
  options.onCallbackServer?.(server);
@@ -14354,7 +14455,7 @@ async function runRunnerInteractiveOAuth(options) {
14354
14455
  if (timeoutId !== void 0) clearTimeout(timeoutId);
14355
14456
  }), new Promise((_, reject) => {
14356
14457
  timeoutId = setTimeout(() => {
14357
- reject(/* @__PURE__ */ new Error(`OAuth callback timed out after ${Math.round(timeoutMs / 1e3)}s`));
14458
+ reject(new OAuthCallbackTimeoutError(timeoutMs));
14358
14459
  }, timeoutMs);
14359
14460
  })]);
14360
14461
  waitForCallback.catch(() => {});
@@ -14385,13 +14486,11 @@ async function runRunnerInteractiveOAuth(options) {
14385
14486
  await server.stop().catch(() => {});
14386
14487
  }
14387
14488
  }
14388
- //#endregion
14389
- //#region src/oauthMessageTone.ts
14489
+ // src/oauthMessageTone.ts
14390
14490
  function oauthMessageToneFor(message, warningText) {
14391
14491
  return message !== null && message === warningText ? "warning" : "info";
14392
14492
  }
14393
- //#endregion
14394
- //#region src/logger.ts
14493
+ // src/logger.ts
14395
14494
  let tuiLoggerInstance;
14396
14495
  function getTuiLogger() {
14397
14496
  if (!tuiLoggerInstance) {
@@ -14408,8 +14507,7 @@ function getTuiLogger() {
14408
14507
  }
14409
14508
  return tuiLoggerInstance;
14410
14509
  }
14411
- //#endregion
14412
- //#region ../../core/node/openUrl.ts
14510
+ // ../../core/node/openUrl.ts
14413
14511
  const OPEN_URL_TIMEOUT_MS = 5e3;
14414
14512
  const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
14415
14513
  function toOpenableHref(href) {
@@ -14437,8 +14535,7 @@ async function openUrl$1(url, timeoutMs = OPEN_URL_TIMEOUT_MS) {
14437
14535
  clearTimeout(timer);
14438
14536
  }
14439
14537
  }
14440
- //#endregion
14441
- //#region src/utils/openUrl.ts
14538
+ // src/utils/openUrl.ts
14442
14539
  function browserOpenFailedMessage(href) {
14443
14540
  return `Could not open a browser automatically. Open this URL manually to authorize: ${href}`;
14444
14541
  }
@@ -14450,13 +14547,11 @@ async function openUrl(url, onFailure) {
14450
14547
  onFailure?.(browserOpenFailedMessage(href));
14451
14548
  }
14452
14549
  }
14453
- //#endregion
14454
- //#region src/utils/tuiOAuth.ts
14550
+ // src/utils/tuiOAuth.ts
14455
14551
  function isStepUpConfirmation(challenge, settings) {
14456
14552
  return isStepUpConfirmation$1(challenge, { enterpriseManaged: settings?.enterpriseManaged });
14457
14553
  }
14458
- //#endregion
14459
- //#region src/components/tabsConfig.ts
14554
+ // src/components/tabsConfig.ts
14460
14555
  const tabs = [
14461
14556
  {
14462
14557
  id: "info",
@@ -14542,8 +14637,7 @@ function tabBarRows(visible, counts, width) {
14542
14637
  }
14543
14638
  return rows;
14544
14639
  }
14545
- //#endregion
14546
- //#region src/components/Tabs.tsx
14640
+ // src/components/Tabs.tsx
14547
14641
  function splitLabelAtAccelerator(label, accelerator) {
14548
14642
  const idx = label.toLowerCase().indexOf(accelerator.toLowerCase());
14549
14643
  if (idx < 0) return {
@@ -14604,8 +14698,7 @@ function Tabs({ activeTab, width, counts = {}, focused = false, showAuth = true,
14604
14698
  })
14605
14699
  });
14606
14700
  }
14607
- //#endregion
14608
- //#region node_modules/ink-scroll-view/dist/index.js
14701
+ // node_modules/ink-scroll-view/dist/index.js
14609
14702
  var MeasurableItem = ({ children, onMeasure, index, width, measureKey }) => {
14610
14703
  const ref = useRef(null);
14611
14704
  useLayoutEffect(() => {
@@ -14887,8 +14980,7 @@ var ScrollView = forwardRef(({ onScroll, onViewportSizeChange, onContentHeightCh
14887
14980
  ...boxProps
14888
14981
  });
14889
14982
  });
14890
- //#endregion
14891
- //#region src/components/InfoTab.tsx
14983
+ // src/components/InfoTab.tsx
14892
14984
  function InfoTab({ serverName, serverConfig, serverSettings = null, serverState, width, height, focused = false, roots = [], onEditRoots }) {
14893
14985
  const headerPairs = serverSettings?.headers ?? [];
14894
14986
  const headersBlock = headerPairs.length > 0 ? /* @__PURE__ */ jsx(Box, {
@@ -15127,8 +15219,7 @@ function InfoTab({ serverName, serverConfig, serverSettings = null, serverState,
15127
15219
  })] }) : null]
15128
15220
  });
15129
15221
  }
15130
- //#endregion
15131
- //#region src/components/SelectableItem.tsx
15222
+ // src/components/SelectableItem.tsx
15132
15223
  function SelectableItem({ isSelected, bold, children }) {
15133
15224
  return /* @__PURE__ */ jsxs(Box, {
15134
15225
  flexShrink: 0,
@@ -15145,8 +15236,7 @@ function SelectableItem({ isSelected, bold, children }) {
15145
15236
  })]
15146
15237
  });
15147
15238
  }
15148
- //#endregion
15149
- //#region src/utils/clipboard.ts
15239
+ // src/utils/clipboard.ts
15150
15240
  const OSC52_LARGE_PAYLOAD_BYTES = 1e5;
15151
15241
  function toCopyText(value) {
15152
15242
  if (typeof value === "string") return value;
@@ -15246,8 +15336,7 @@ function useCopyKeys(value, label) {
15246
15336
  function copyStatusColor(tone) {
15247
15337
  return tone === "success" ? "green" : tone === "warning" ? "yellow" : "red";
15248
15338
  }
15249
- //#endregion
15250
- //#region src/utils/oauthDisplay.ts
15339
+ // src/utils/oauthDisplay.ts
15251
15340
  function formatAuthProtocol(protocol) {
15252
15341
  return protocol === "ema" ? "Enterprise-managed" : "Standard";
15253
15342
  }
@@ -15269,8 +15358,7 @@ function formatScopes(state) {
15269
15358
  const scopes = (state.grantedScope ?? state.configuredScope)?.split(" ").filter(Boolean);
15270
15359
  return scopes && scopes.length > 0 ? scopes.join(", ") : void 0;
15271
15360
  }
15272
- //#endregion
15273
- //#region src/utils/errorText.ts
15361
+ // src/utils/errorText.ts
15274
15362
  function errorMessage$1(err) {
15275
15363
  return redactUrlsInText(err instanceof Error ? err.message : String(err));
15276
15364
  }
@@ -15280,8 +15368,128 @@ function redactErrorText(text) {
15280
15368
  function redactedJson(value) {
15281
15369
  return redactUrlsInText(JSON.stringify(value, null, 2) ?? String(value));
15282
15370
  }
15283
- //#endregion
15284
- //#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();
15285
15493
  function OAuthDetailRow({ label, value }) {
15286
15494
  return /* @__PURE__ */ jsxs(Box, {
15287
15495
  flexDirection: "row",
@@ -15367,6 +15575,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
15367
15575
  inspectorClient.removeEventListener("oauthComplete", update);
15368
15576
  };
15369
15577
  }, [inspectorClient, refreshOAuthState]);
15578
+ const fetchRefusals = useStoreSnapshot(inspectorClient, "fetchRefused", readFetchRefusals, NO_REFUSALS);
15370
15579
  const accessToken = oauthState?.tokens?.access_token;
15371
15580
  const { handleCopyKey, status: copyStatus } = useCopyKeys(accessToken, "access token");
15372
15581
  useInput((input, key) => {
@@ -15438,6 +15647,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
15438
15647
  })
15439
15648
  });
15440
15649
  const scopes = oauthState ? formatScopes(oauthState) : void 0;
15650
+ const tokenDetails = oauthState?.tokens?.access_token ? accessTokenDetailLines(summarizeAccessToken(oauthState.tokens), Date.now()) : [];
15441
15651
  return /* @__PURE__ */ jsxs(Box, {
15442
15652
  width,
15443
15653
  height,
@@ -15476,6 +15686,19 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
15476
15686
  color: oauthMessageTone === "warning" ? "yellow" : "cyan",
15477
15687
  children: oauthMessage
15478
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
+ }),
15479
15702
  pendingStepUp ? /* @__PURE__ */ jsxs(Box, {
15480
15703
  marginTop: 1,
15481
15704
  flexDirection: "column",
@@ -15537,53 +15760,68 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
15537
15760
  flexDirection: "column",
15538
15761
  marginTop: 1,
15539
15762
  gap: 0,
15540
- children: [/* @__PURE__ */ jsx(Text, {
15541
- bold: true,
15542
- children: "OAuth Details"
15543
- }), /* @__PURE__ */ jsxs(Box, {
15544
- marginTop: 1,
15545
- flexDirection: "column",
15546
- paddingLeft: 0,
15547
- gap: 0,
15548
- children: [
15549
- /* @__PURE__ */ jsx(OAuthDetailRow, {
15550
- label: "Protocol",
15551
- value: formatAuthProtocol(oauthState.protocol)
15552
- }),
15553
- /* @__PURE__ */ jsx(OAuthDetailRow, {
15554
- label: "Status",
15555
- value: oauthState.authorized ? "Authorized" : "Not authorized"
15556
- }),
15557
- oauthState.client?.clientId && /* @__PURE__ */ jsx(OAuthDetailRow, {
15558
- label: "Client ID",
15559
- value: oauthState.client.clientId
15560
- }),
15561
- oauthState.client?.registrationKind && /* @__PURE__ */ jsx(OAuthDetailRow, {
15562
- label: "Client registration",
15563
- value: formatClientRegistrationKind(oauthState.client.registrationKind)
15564
- }),
15565
- oauthState.protocol === "ema" && oauthState.ema?.idpSession && /* @__PURE__ */ jsx(OAuthDetailRow, {
15566
- label: "IdP session",
15567
- value: formatIdpSession(oauthState.ema.idpSession)
15568
- }),
15569
- oauthState.authorizationServerMetadata?.authorization_endpoint && /* @__PURE__ */ jsx(OAuthDetailRow, {
15570
- label: "Auth URL",
15571
- value: oauthState.authorizationServerMetadata.authorization_endpoint
15572
- }),
15573
- scopes && /* @__PURE__ */ jsx(OAuthDetailRow, {
15574
- label: "Scopes",
15575
- value: scopes
15576
- }),
15577
- accessToken && /* @__PURE__ */ jsx(OAuthDetailRow, {
15578
- label: "Access token",
15579
- value: `${accessToken.slice(0, 24)}…`
15580
- }),
15581
- accessToken && copyStatus && /* @__PURE__ */ jsx(Text, {
15582
- color: copyStatusColor(copyStatus.tone),
15583
- children: copyStatus.message
15584
- })
15585
- ]
15586
- })]
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
+ ]
15587
15825
  }) : oauthStatus !== "authenticating" && /* @__PURE__ */ jsxs(Box, {
15588
15826
  marginTop: 1,
15589
15827
  flexDirection: "column",
@@ -15645,8 +15883,7 @@ function AuthTab({ serverName, inspectorClient, oauthStatus, oauthMessage, oauth
15645
15883
  ]
15646
15884
  });
15647
15885
  }
15648
- //#endregion
15649
- //#region src/hooks/useSelectableList.ts
15886
+ // src/hooks/useSelectableList.ts
15650
15887
  function clampFirstVisible(first, selected, visibleCount) {
15651
15888
  if (selected < first) return selected;
15652
15889
  if (selected >= first + visibleCount) return selected - visibleCount + 1;
@@ -15682,8 +15919,7 @@ function useSelectableList(itemCount, visibleCount, options) {
15682
15919
  setSelection
15683
15920
  };
15684
15921
  }
15685
- //#endregion
15686
- //#region src/hooks/useListFilter.ts
15922
+ // src/hooks/useListFilter.ts
15687
15923
  function printable(input) {
15688
15924
  return input.replace(/[\u0000-\u001f\u007f]/g, "");
15689
15925
  }
@@ -15810,8 +16046,7 @@ function ListFilterBar({ query, editing, focused }) {
15810
16046
  function filterCount(active, shown, total) {
15811
16047
  return active ? `${shown}/${total}` : String(total);
15812
16048
  }
15813
- //#endregion
15814
- //#region src/components/ResourcesTab.tsx
16049
+ // src/components/ResourcesTab.tsx
15815
16050
  function resourceFilterFields(item) {
15816
16051
  return item.type === "resource" ? [
15817
16052
  item.data.name,
@@ -16151,8 +16386,7 @@ function ResourcesTab({ resources, resourceTemplates = [], inspectorClient, widt
16151
16386
  })]
16152
16387
  });
16153
16388
  }
16154
- //#endregion
16155
- //#region src/components/PromptsTab.tsx
16389
+ // src/components/PromptsTab.tsx
16156
16390
  function promptFilterFields(prompt) {
16157
16391
  return [prompt.name, prompt.title];
16158
16392
  }
@@ -16368,8 +16602,7 @@ function PromptsTab({ prompts, inspectorClient, width, height, focusedPane = nul
16368
16602
  })]
16369
16603
  });
16370
16604
  }
16371
- //#endregion
16372
- //#region ../../core/extension/skills/verification.ts
16605
+ // ../../core/extension/skills/verification.ts
16373
16606
  const DEFAULT_SKILL_BUDGET_HINT = {
16374
16607
  raise: "with the server's skillCatalogMaxSkills / skillCatalogMaxBytes settings",
16375
16608
  verifyOne: "by verifying this skill alone"
@@ -16542,8 +16775,7 @@ async function verifySkills(client, entries, metadata, budgetHint = DEFAULT_SKIL
16542
16775
  }
16543
16776
  return reports;
16544
16777
  }
16545
- //#endregion
16546
- //#region src/components/SkillsTab.tsx
16778
+ // src/components/SkillsTab.tsx
16547
16779
  function skillFilterFields(skill) {
16548
16780
  return [skillDisplayName(skill), skill.frontmatter.name];
16549
16781
  }
@@ -16998,8 +17230,7 @@ function SkillsTab({ skills, pageCount, loadError = null, inspectorClient, width
16998
17230
  })]
16999
17231
  });
17000
17232
  }
17001
- //#endregion
17002
- //#region ../../core/json/schemaLint.ts
17233
+ // ../../core/json/schemaLint.ts
17003
17234
  const BOOLEAN_VALUED_KEYWORDS = /* @__PURE__ */ new Set([
17004
17235
  "additionalProperties",
17005
17236
  "unevaluatedProperties",
@@ -17193,8 +17424,7 @@ function lintToolSchemas(tool) {
17193
17424
  if (tool.outputSchema !== void 0) lintSchema(tool.outputSchema, "outputSchema", findings);
17194
17425
  return findings;
17195
17426
  }
17196
- //#endregion
17197
- //#region src/components/ToolsTab.tsx
17427
+ // src/components/ToolsTab.tsx
17198
17428
  const SEVERITY_MARKER = {
17199
17429
  error: {
17200
17430
  glyph: "!",
@@ -17458,8 +17688,7 @@ function ToolsTab({ tools, isConnected, width, height, focusedPane = null, onTes
17458
17688
  })]
17459
17689
  });
17460
17690
  }
17461
- //#endregion
17462
- //#region src/components/NotificationsTab.tsx
17691
+ // src/components/NotificationsTab.tsx
17463
17692
  function NotificationsTab({ stderrLogs, width, height, onCountChange, focused = false }) {
17464
17693
  const scrollViewRef = useRef(null);
17465
17694
  const onCountChangeRef = useRef(onCountChange);
@@ -17547,8 +17776,7 @@ function layoutBody(body, maxLines = 500, maxLineChars = MAX_BODY_LINE_CHARS) {
17547
17776
  totalLines: all.length
17548
17777
  };
17549
17778
  }
17550
- //#endregion
17551
- //#region src/components/BodyLines.tsx
17779
+ // src/components/BodyLines.tsx
17552
17780
  function BodyLines({ body, keyPrefix }) {
17553
17781
  const { lines, hiddenLines, totalLines } = layoutBody(body);
17554
17782
  return /* @__PURE__ */ jsxs(Fragment, { children: [lines.map((line, idx) => /* @__PURE__ */ jsx(Box, {
@@ -17575,8 +17803,7 @@ function BodyLines({ body, keyPrefix }) {
17575
17803
  })
17576
17804
  })] });
17577
17805
  }
17578
- //#endregion
17579
- //#region src/components/HistoryTab.tsx
17806
+ // src/components/HistoryTab.tsx
17580
17807
  function HistoryTab({ messages, width, height, onCountChange, focusedPane = null, onViewDetails, modalOpen = false }) {
17581
17808
  const visibleCount = Math.max(1, height - 7);
17582
17809
  const { selectedIndex, firstVisible, setSelection } = useSelectableList(messages.length, visibleCount);
@@ -17784,8 +18011,7 @@ function HistoryTab({ messages, width, height, onCountChange, focusedPane = null
17784
18011
  })]
17785
18012
  });
17786
18013
  }
17787
- //#endregion
17788
- //#region src/components/RequestsTab.tsx
18014
+ // src/components/RequestsTab.tsx
17789
18015
  function RequestsTab({ requests, width, height, onCountChange, focusedPane = null, onViewDetails, modalOpen = false }) {
17790
18016
  const visibleCount = Math.max(1, height - 7);
17791
18017
  const { selectedIndex, firstVisible, setSelection } = useSelectableList(requests.length, visibleCount);
@@ -18081,8 +18307,7 @@ function RequestsTab({ requests, width, height, onCountChange, focusedPane = nul
18081
18307
  })]
18082
18308
  });
18083
18309
  }
18084
- //#endregion
18085
- //#region node_modules/ink-form/lib/FormHeader.js
18310
+ // node_modules/ink-form/lib/FormHeader.js
18086
18311
  const FormHeader = (props) => {
18087
18312
  const sections = props.form.sections;
18088
18313
  useInput((input, key) => {
@@ -18101,8 +18326,7 @@ const FormHeader = (props) => {
18101
18326
  underline: props.currentTab === id
18102
18327
  }, section.title), React$1.createElement(Text, null, " "))) : React$1.createElement(Box, null, React$1.createElement(Text, null, "Editing ", props.editingField)))));
18103
18328
  };
18104
- //#endregion
18105
- //#region node_modules/chalk/source/vendor/ansi-styles/index.js
18329
+ // node_modules/chalk/source/vendor/ansi-styles/index.js
18106
18330
  const ANSI_BACKGROUND_OFFSET = 10;
18107
18331
  const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
18108
18332
  const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
@@ -18265,8 +18489,7 @@ function assembleStyles() {
18265
18489
  return styles$1;
18266
18490
  }
18267
18491
  const ansiStyles = assembleStyles();
18268
- //#endregion
18269
- //#region node_modules/chalk/source/vendor/supports-color/index.js
18492
+ // node_modules/chalk/source/vendor/supports-color/index.js
18270
18493
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
18271
18494
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
18272
18495
  const position = argv.indexOf(prefix + flag);
@@ -18353,8 +18576,7 @@ const supportsColor = {
18353
18576
  stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
18354
18577
  stderr: createSupportsColor({ isTTY: tty.isatty(2) })
18355
18578
  };
18356
- //#endregion
18357
- //#region node_modules/chalk/source/utilities.js
18579
+ // node_modules/chalk/source/utilities.js
18358
18580
  function stringReplaceAll(string, substring, replacer) {
18359
18581
  let index = string.indexOf(substring);
18360
18582
  if (index === -1) return string;
@@ -18381,8 +18603,7 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
18381
18603
  returnValue += string.slice(endIndex);
18382
18604
  return returnValue;
18383
18605
  }
18384
- //#endregion
18385
- //#region node_modules/chalk/source/index.js
18606
+ // node_modules/chalk/source/index.js
18386
18607
  const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
18387
18608
  const GENERATOR = Symbol("GENERATOR");
18388
18609
  const STYLER = Symbol("STYLER");
@@ -18503,8 +18724,7 @@ const applyStyle = (self, string) => {
18503
18724
  Object.defineProperties(createChalk.prototype, styles);
18504
18725
  const chalk = createChalk();
18505
18726
  createChalk({ level: stderrColor ? stderrColor.level : 0 });
18506
- //#endregion
18507
- //#region node_modules/ink-text-input/build/index.js
18727
+ // node_modules/ink-text-input/build/index.js
18508
18728
  function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
18509
18729
  const [state, setState] = useState({
18510
18730
  cursorOffset: (originalValue || "").length,
@@ -18573,8 +18793,7 @@ function TextInput({ value: originalValue, placeholder = "", focus = true, mask,
18573
18793
  }, { isActive: focus });
18574
18794
  return React.createElement(Text, null, placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue);
18575
18795
  }
18576
- //#endregion
18577
- //#region node_modules/ink-form/lib/NumberFieldRenderer.js
18796
+ // node_modules/ink-form/lib/NumberFieldRenderer.js
18578
18797
  const FLOAT_REGEX = /^-?((\d+)|(\d*\.\d+))$/;
18579
18798
  const INTEGER_REGEX = /^-?\d+$/;
18580
18799
  const NumberFieldRenderer = (props) => {
@@ -18623,8 +18842,7 @@ const NumberFieldRenderer = (props) => {
18623
18842
  onSubmit: () => props.onSetEditingField(void 0)
18624
18843
  })), React.createElement(Box, null, React.createElement(Text, { dimColor: true }, "Press UP/DOWN to increase or decrease the value.")));
18625
18844
  };
18626
- //#endregion
18627
- //#region node_modules/ink-form/lib/managers/FloatFormFieldManager.js
18845
+ // node_modules/ink-form/lib/managers/FloatFormFieldManager.js
18628
18846
  var FloatFormFieldManager = class {
18629
18847
  type = "float";
18630
18848
  renderField = (props) => React.createElement(NumberFieldRenderer, {
@@ -18633,8 +18851,7 @@ var FloatFormFieldManager = class {
18633
18851
  });
18634
18852
  renderValue = (props) => React.createElement(React.Fragment, null, props.value);
18635
18853
  };
18636
- //#endregion
18637
- //#region node_modules/ink-form/lib/managers/IntegerFormFieldManager.js
18854
+ // node_modules/ink-form/lib/managers/IntegerFormFieldManager.js
18638
18855
  var IntegerFormFieldManager = class {
18639
18856
  type = "integer";
18640
18857
  renderField = (props) => React.createElement(NumberFieldRenderer, {
@@ -18643,16 +18860,14 @@ var IntegerFormFieldManager = class {
18643
18860
  });
18644
18861
  renderValue = (props) => React.createElement(React.Fragment, null, props.value);
18645
18862
  };
18646
- //#endregion
18647
- //#region node_modules/is-unicode-supported/index.js
18863
+ // node_modules/is-unicode-supported/index.js
18648
18864
  function isUnicodeSupported() {
18649
18865
  const { env } = process$1;
18650
18866
  const { TERM, TERM_PROGRAM } = env;
18651
18867
  if (process$1.platform !== "win32") return TERM !== "linux";
18652
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";
18653
18869
  }
18654
- //#endregion
18655
- //#region node_modules/figures/index.js
18870
+ // node_modules/figures/index.js
18656
18871
  const common = {
18657
18872
  circleQuestionMark: "(?)",
18658
18873
  questionMarkPrefix: "(?)",
@@ -18931,18 +19146,15 @@ const fallbackSymbols = {
18931
19146
  };
18932
19147
  const figures = isUnicodeSupported() ? mainSymbols : fallbackSymbols;
18933
19148
  Object.entries(specialMainSymbols);
18934
- //#endregion
18935
- //#region node_modules/ink-select-input/build/Indicator.js
19149
+ // node_modules/ink-select-input/build/Indicator.js
18936
19150
  function Indicator({ isSelected = false }) {
18937
19151
  return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures.pointer) : React.createElement(Text, null, " "));
18938
19152
  }
18939
- //#endregion
18940
- //#region node_modules/ink-select-input/build/Item.js
19153
+ // node_modules/ink-select-input/build/Item.js
18941
19154
  function Item({ isSelected = false, label }) {
18942
19155
  return React$1.createElement(Text, { color: isSelected ? "blue" : void 0 }, label);
18943
19156
  }
18944
- //#endregion
18945
- //#region node_modules/to-rotated/index.js
19157
+ // node_modules/to-rotated/index.js
18946
19158
  function toRotated(array, steps) {
18947
19159
  if (!Array.isArray(array)) throw new TypeError(`Expected an array, got \`${typeof array}\`.`);
18948
19160
  if (!Number.isSafeInteger(steps)) throw new TypeError(`The \`steps\` parameter must be an integer, got ${steps}.`);
@@ -18952,8 +19164,7 @@ function toRotated(array, steps) {
18952
19164
  if (normalizedSteps === 0) return [...array];
18953
19165
  return [...array.slice(-normalizedSteps), ...array.slice(0, -normalizedSteps)];
18954
19166
  }
18955
- //#endregion
18956
- //#region node_modules/ink-select-input/build/SelectInput.js
19167
+ // node_modules/ink-select-input/build/SelectInput.js
18957
19168
  function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator, itemComponent = Item, limit: customLimit, onSelect, onHighlight }) {
18958
19169
  const hasLimit = typeof customLimit === "number" && items.length > customLimit;
18959
19170
  const limit = hasLimit ? Math.min(customLimit, items.length) : items.length;
@@ -19020,8 +19231,7 @@ function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicator
19020
19231
  }));
19021
19232
  }));
19022
19233
  }
19023
- //#endregion
19024
- //#region node_modules/ink-form/lib/managers/SelectFormFieldManager.js
19234
+ // node_modules/ink-form/lib/managers/SelectFormFieldManager.js
19025
19235
  var SelectFormFieldManager = class {
19026
19236
  type = "select";
19027
19237
  renderField = (props) => React.createElement(Box, {
@@ -19037,8 +19247,7 @@ var SelectFormFieldManager = class {
19037
19247
  }));
19038
19248
  renderValue = (props) => React.createElement(React.Fragment, null, props.field.options.find((option) => option.value === props.value)?.label ?? props.value ?? "No value");
19039
19249
  };
19040
- //#endregion
19041
- //#region node_modules/ink-form/lib/managers/StringFormFieldManager.js
19250
+ // node_modules/ink-form/lib/managers/StringFormFieldManager.js
19042
19251
  var StringFormFieldManager = class {
19043
19252
  type = "string";
19044
19253
  renderField = (props) => React.createElement(Box, {
@@ -19057,8 +19266,7 @@ var StringFormFieldManager = class {
19057
19266
  }));
19058
19267
  renderValue = (props) => React.createElement(Transform, { transform: props.value !== void 0 && props.field.mask ? (text) => text.split("").map((char) => "*").join("") : (text) => text }, props.value);
19059
19268
  };
19060
- //#endregion
19061
- //#region node_modules/ink-form/lib/managers/BooleanFormFieldManager.js
19269
+ // node_modules/ink-form/lib/managers/BooleanFormFieldManager.js
19062
19270
  var BooleanFormFieldManager = class {
19063
19271
  type = "boolean";
19064
19272
  renderField = (props) => {
@@ -19074,8 +19282,7 @@ var BooleanFormFieldManager = class {
19074
19282
  };
19075
19283
  renderValue = (props) => React.createElement(Text, null, props.value === void 0 ? "[Not set]" : props.value ? "[True]" : "[False]");
19076
19284
  };
19077
- //#endregion
19078
- //#region node_modules/ink-form/lib/managers/managers.js
19285
+ // node_modules/ink-form/lib/managers/managers.js
19079
19286
  const managers = [
19080
19287
  new FloatFormFieldManager(),
19081
19288
  new IntegerFormFieldManager(),
@@ -19086,8 +19293,7 @@ const managers = [
19086
19293
  const getManager = (formFieldType, customManagers = []) => {
19087
19294
  return [...managers, ...customManagers].find((manager) => manager.type === formFieldType);
19088
19295
  };
19089
- //#endregion
19090
- //#region node_modules/ink-form/lib/DescriptionRenderer.js
19296
+ // node_modules/ink-form/lib/DescriptionRenderer.js
19091
19297
  const DescriptionRenderer = (props) => {
19092
19298
  if (!props.description) return null;
19093
19299
  else if (props.description.type) return props.description;
@@ -19098,8 +19304,7 @@ const DescriptionRenderer = (props) => {
19098
19304
  }, React.createElement(Text, null, line))));
19099
19305
  else return React.createElement(Text, null, props.description);
19100
19306
  };
19101
- //#endregion
19102
- //#region node_modules/ink-form/lib/FormFieldRenderer.js
19307
+ // node_modules/ink-form/lib/FormFieldRenderer.js
19103
19308
  const FormFieldRenderer = (props) => {
19104
19309
  const manager = getManager(props.field.type, props.customManagers);
19105
19310
  const [error, setError] = useState();
@@ -19165,13 +19370,11 @@ const FormFieldRenderer = (props) => {
19165
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."))));
19166
19371
  }
19167
19372
  };
19168
- //#endregion
19169
- //#region node_modules/ink-form/lib/canSubmit.js
19373
+ // node_modules/ink-form/lib/canSubmit.js
19170
19374
  const canSubmit = (form, value) => {
19171
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);
19172
19376
  };
19173
- //#endregion
19174
- //#region node_modules/ink-form/lib/SubmitButton.js
19377
+ // node_modules/ink-form/lib/SubmitButton.js
19175
19378
  const SubmitButton = (props) => {
19176
19379
  const { isFocused } = useFocus({ isActive: props.canSubmit });
19177
19380
  useInput((input, key) => {
@@ -19190,8 +19393,7 @@ const SubmitButton = (props) => {
19190
19393
  underline: isFocused
19191
19394
  }, props.canSubmit ? "Submit form" : "Cannot submit form yet")));
19192
19395
  };
19193
- //#endregion
19194
- //#region node_modules/ink-form/lib/Form.js
19396
+ // node_modules/ink-form/lib/Form.js
19195
19397
  const Form = (props) => {
19196
19398
  const isControlled = props.value !== void 0;
19197
19399
  const [currentTab, setCurrentTab] = useState(0);
@@ -19251,8 +19453,29 @@ const Form = (props) => {
19251
19453
  onSubmit: () => props.onSubmit?.(value)
19252
19454
  })));
19253
19455
  };
19254
- //#endregion
19255
- //#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
19256
19479
  function toSelectOptions(values, names) {
19257
19480
  const useNames = names !== void 0 && names.length === values.length;
19258
19481
  return values.map((val, index) => ({
@@ -19260,6 +19483,19 @@ function toSelectOptions(values, names) {
19260
19483
  value: String(val)
19261
19484
  }));
19262
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
+ }
19263
19499
  function generatedNames(base, branches) {
19264
19500
  const declared = [...Object.keys(base.properties ?? {}), ...branches.flatMap((branch) => branch.declaredFields)];
19265
19501
  let variant = "__variant";
@@ -19296,6 +19532,12 @@ function constOf(schema) {
19296
19532
  if (typeof schema !== "object" || schema === null) return void 0;
19297
19533
  return schema.const;
19298
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
+ }
19299
19541
  function schemaToForm(schema, toolName) {
19300
19542
  const title = `Test Tool: ${toolName}`;
19301
19543
  if (!schema) return {
@@ -19351,7 +19593,7 @@ function schemaToForm(schema, toolName) {
19351
19593
  }
19352
19594
  function decodeFormValues(schema, values) {
19353
19595
  const { base, branches } = resolveRootUnion(schema ?? {});
19354
- 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));
19355
19597
  const { variant, prefix } = generatedNames(base, branches);
19356
19598
  const branchIndex = selectedBranchIndex(base, branches, values);
19357
19599
  const branch = branches[branchIndex];
@@ -19361,7 +19603,9 @@ function decodeFormValues(schema, values) {
19361
19603
  });
19362
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)]);
19363
19605
  /* v8 ignore next -- an offerable branch always carries properties */
19364
- 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);
19365
19609
  }
19366
19610
  function selectedBranchIndex(base, branches, values) {
19367
19611
  const { variant } = generatedNames(base, branches);
@@ -19373,12 +19617,24 @@ function applyConstants(properties, values, required) {
19373
19617
  if (pinned.length === 0) return values;
19374
19618
  return Object.fromEntries([...Object.entries(values), ...pinned.map(([name, schema]) => [name, constOf(schema)])]);
19375
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
+ }
19376
19632
  function buildFields(schema, { optional = false } = {}) {
19377
19633
  const fields = [];
19378
19634
  const properties = schema.properties || {};
19379
19635
  const required = Array.isArray(schema.required) ? schema.required : [];
19380
19636
  for (const [key, prop] of Object.entries(properties)) {
19381
- const property = normalizeNullableUnion(typeof prop === "object" && prop !== null ? prop : {});
19637
+ const property = declarationOf(prop);
19382
19638
  const baseField = {
19383
19639
  name: key,
19384
19640
  label: property.title || key,
@@ -19399,12 +19655,18 @@ function buildFields(schema, { optional = false } = {}) {
19399
19655
  });
19400
19656
  continue;
19401
19657
  }
19402
- if (property.type === "array" && property.items?.enum) field = {
19403
- type: "select",
19404
- ...baseField,
19405
- options: toSelectOptions(property.items.enum, property.items.enumNames)
19406
- };
19407
- 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 = {
19408
19670
  type: "select",
19409
19671
  ...baseField,
19410
19672
  /* v8 ignore next -- guarded by `isStringEnum(property.enum)` above */
@@ -19464,16 +19726,95 @@ function missingRequiredFields(schema, decoded, rawValues = {}) {
19464
19726
  return value === void 0;
19465
19727
  });
19466
19728
  }
19467
- //#endregion
19468
- //#region src/utils/formHeader.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
19469
19811
  function untitledForm(form) {
19470
19812
  return {
19471
19813
  ...form,
19472
19814
  title: void 0
19473
19815
  };
19474
19816
  }
19475
- //#endregion
19476
- //#region ../../core/mcp/resultFile.ts
19817
+ // ../../core/mcp/resultFile.ts
19477
19818
  var RawResultUnavailableError = class extends Error {
19478
19819
  method;
19479
19820
  binaryCount;
@@ -19519,8 +19860,7 @@ function renderResultForFile(result, method, format) {
19519
19860
  function renderedByteLength(data) {
19520
19861
  return typeof data === "string" ? new TextEncoder().encode(data).length : data.length;
19521
19862
  }
19522
- //#endregion
19523
- //#region src/utils/saveResult.ts
19863
+ // src/utils/saveResult.ts
19524
19864
  function fileSafe(name) {
19525
19865
  const safe = name.replace(/[^A-Za-z0-9._-]/g, "_");
19526
19866
  return safe === "" ? "tool" : safe;
@@ -19564,8 +19904,7 @@ async function writeResult(result, path, format, cwd) {
19564
19904
  function errorMessage(err) {
19565
19905
  return err instanceof Error ? err.message : String(err);
19566
19906
  }
19567
- //#endregion
19568
- //#region src/components/SaveResultBar.tsx
19907
+ // src/components/SaveResultBar.tsx
19569
19908
  function SaveResultBar({ prompt, status }) {
19570
19909
  if (prompt) return /* @__PURE__ */ jsxs(Box, {
19571
19910
  flexShrink: 0,
@@ -19600,9 +19939,8 @@ function SaveResultBar({ prompt, status }) {
19600
19939
  });
19601
19940
  return null;
19602
19941
  }
19603
- //#endregion
19604
- //#region src/components/ToolTestModal.tsx
19605
- function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
19942
+ // src/components/ToolTestModal.tsx
19943
+ function ToolTestModal({ tool, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
19606
19944
  const [state, setState] = useState("form");
19607
19945
  const [result, setResult] = useState(null);
19608
19946
  const [savePrompt, setSavePromptState] = useState(null);
@@ -19676,7 +20014,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19676
20014
  }
19677
20015
  }
19678
20016
  };
19679
- useInput((input, key) => handleInputRef.current(input, key), { isActive: true });
20017
+ useInput((input, key) => handleInputRef.current(input, key), { isActive: inputActive });
19680
20018
  const openSavePrompt = () => {
19681
20019
  if (!result?.callResult) {
19682
20020
  setSaveStatus({
@@ -19748,6 +20086,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19748
20086
  }
19749
20087
  };
19750
20088
  const handleFormSubmit = async (rawValues) => {
20089
+ if (!inputActive) return;
19751
20090
  if (!inspectorClient || !tool) return;
19752
20091
  const values = decodeFormValues(inputSchema, rawValues);
19753
20092
  const missing = missingRequiredFields(inputSchema, values, rawValues);
@@ -19761,6 +20100,17 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19761
20100
  setState("results");
19762
20101
  return;
19763
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
+ }
19764
20114
  setState("loading");
19765
20115
  const startTime = Date.now();
19766
20116
  try {
@@ -19851,6 +20201,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19851
20201
  width: "100%",
19852
20202
  children: /* @__PURE__ */ jsx(Form, {
19853
20203
  form: untitledForm(formStructure),
20204
+ customManagers: FORM_FIELD_MANAGERS,
19854
20205
  onSubmit: (value) => void handleFormSubmit(value)
19855
20206
  })
19856
20207
  }),
@@ -19958,8 +20309,7 @@ function ToolTestModal({ tool, inspectorClient, width, height, onClose, onAuthRe
19958
20309
  })
19959
20310
  });
19960
20311
  }
19961
- //#endregion
19962
- //#region src/utils/uriTemplateToForm.ts
20312
+ // src/utils/uriTemplateToForm.ts
19963
20313
  function uriTemplateToForm(uriTemplate, templateName) {
19964
20314
  let fields = [];
19965
20315
  try {
@@ -19983,15 +20333,14 @@ function uriTemplateToForm(uriTemplate, templateName) {
19983
20333
  sections
19984
20334
  };
19985
20335
  }
19986
- //#endregion
19987
- //#region src/components/ResourceTestModal.tsx
20336
+ // src/components/ResourceTestModal.tsx
19988
20337
  function getErrorMessage$1(error) {
19989
20338
  if (error instanceof Error) return error.message;
19990
20339
  if (typeof error === "string") return error;
19991
20340
  if (error && typeof error === "object" && "message" in error) return String(error.message);
19992
20341
  return "Unknown error";
19993
20342
  }
19994
- function ResourceTestModal({ template, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
20343
+ function ResourceTestModal({ template, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
19995
20344
  const [state, setState] = useState("form");
19996
20345
  const [result, setResult] = useState(null);
19997
20346
  const scrollViewRef = React.useRef(null);
@@ -20038,8 +20387,9 @@ function ResourceTestModal({ template, inspectorClient, width, height, onClose,
20038
20387
  scrollViewRef.current?.scrollBy(-viewportHeight);
20039
20388
  }
20040
20389
  }
20041
- }, { isActive: true });
20390
+ }, { isActive: inputActive });
20042
20391
  const handleFormSubmit = async (values) => {
20392
+ if (!inputActive) return;
20043
20393
  if (!inspectorClient || !template) return;
20044
20394
  const unmetGroups = unmetRequiredGroups(requiredGroups(template.uriTemplate), values);
20045
20395
  if (unmetGroups.length > 0) {
@@ -20267,8 +20617,7 @@ function ResourceTestModal({ template, inspectorClient, width, height, onClose,
20267
20617
  })
20268
20618
  });
20269
20619
  }
20270
- //#endregion
20271
- //#region src/utils/promptArgsToForm.ts
20620
+ // src/utils/promptArgsToForm.ts
20272
20621
  function promptArgsToForm(promptArguments, promptName) {
20273
20622
  const fields = [];
20274
20623
  if (!promptArguments || promptArguments.length === 0) return {
@@ -20297,15 +20646,14 @@ function promptArgsToForm(promptArguments, promptName) {
20297
20646
  sections
20298
20647
  };
20299
20648
  }
20300
- //#endregion
20301
- //#region src/components/PromptTestModal.tsx
20649
+ // src/components/PromptTestModal.tsx
20302
20650
  function getErrorMessage(error) {
20303
20651
  if (error instanceof Error) return error.message;
20304
20652
  if (typeof error === "string") return error;
20305
20653
  if (error && typeof error === "object" && "message" in error) return String(error.message);
20306
20654
  return "Unknown error";
20307
20655
  }
20308
- function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAuthRecoveryRequired }) {
20656
+ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, inputActive = true, onAuthRecoveryRequired }) {
20309
20657
  const [state, setState] = useState("form");
20310
20658
  const [result, setResult] = useState(null);
20311
20659
  const scrollViewRef = React.useRef(null);
@@ -20352,8 +20700,9 @@ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAu
20352
20700
  scrollViewRef.current?.scrollBy(-viewportHeight);
20353
20701
  }
20354
20702
  }
20355
- }, { isActive: true });
20703
+ }, { isActive: inputActive });
20356
20704
  const handleFormSubmit = async (values) => {
20705
+ if (!inputActive) return;
20357
20706
  if (!inspectorClient || !prompt) return;
20358
20707
  setState("loading");
20359
20708
  const startTime = Date.now();
@@ -20552,9 +20901,8 @@ function PromptTestModal({ prompt, inspectorClient, width, height, onClose, onAu
20552
20901
  })
20553
20902
  });
20554
20903
  }
20555
- //#endregion
20556
- //#region src/components/DetailsModal.tsx
20557
- function DetailsModal({ title, content, width, height, onClose, copyText }) {
20904
+ // src/components/DetailsModal.tsx
20905
+ function DetailsModal({ title, content, width, height, onClose, inputActive = true, copyText }) {
20558
20906
  const scrollViewRef = useRef(null);
20559
20907
  const { handleCopyKey, status: copyStatus } = useCopyKeys(copyText, "details");
20560
20908
  const [terminalDimensions, setTerminalDimensions] = React.useState({
@@ -20586,7 +20934,7 @@ function DetailsModal({ title, content, width, height, onClose, copyText }) {
20586
20934
  const viewportHeight = scrollViewRef.current?.getViewportHeight() || 1;
20587
20935
  scrollViewRef.current?.scrollBy(-viewportHeight);
20588
20936
  }
20589
- }, { isActive: true });
20937
+ }, { isActive: inputActive });
20590
20938
  const modalWidth = terminalDimensions.width - 2;
20591
20939
  const modalHeight = terminalDimensions.height - 2;
20592
20940
  return /* @__PURE__ */ jsx(Box, {
@@ -20643,8 +20991,7 @@ function DetailsModal({ title, content, width, height, onClose, copyText }) {
20643
20991
  })
20644
20992
  });
20645
20993
  }
20646
- //#endregion
20647
- //#region src/utils/keybindings.ts
20994
+ // src/utils/keybindings.ts
20648
20995
  function tabAcceleratorBinding(visible) {
20649
20996
  return {
20650
20997
  keys: visible.map((tab) => tab.accelerator).join(" "),
@@ -20891,10 +21238,9 @@ function keyColumnWidth(sections) {
20891
21238
  for (const section of sections) for (const binding of section.bindings) width = Math.max(width, binding.keys.length);
20892
21239
  return width;
20893
21240
  }
20894
- //#endregion
20895
- //#region src/components/HelpOverlay.tsx
21241
+ // src/components/HelpOverlay.tsx
20896
21242
  const COLUMN_GAP = 2;
20897
- function HelpOverlay({ sections, width, height, onClose }) {
21243
+ function HelpOverlay({ sections, width, height, onClose, inputActive = true }) {
20898
21244
  const scrollViewRef = useRef(null);
20899
21245
  const keysWidth = keyColumnWidth(sections) + COLUMN_GAP;
20900
21246
  useInput((input, key) => {
@@ -20904,7 +21250,7 @@ function HelpOverlay({ sections, width, height, onClose }) {
20904
21250
  else if (key.upArrow) view?.scrollBy(-1);
20905
21251
  else if (key.pageDown) view?.scrollBy(view.getViewportHeight());
20906
21252
  else if (key.pageUp) view?.scrollBy(-view.getViewportHeight());
20907
- });
21253
+ }, { isActive: inputActive });
20908
21254
  return /* @__PURE__ */ jsx(Box, {
20909
21255
  position: "absolute",
20910
21256
  width,
@@ -20963,8 +21309,7 @@ function HelpOverlay({ sections, width, height, onClose }) {
20963
21309
  })
20964
21310
  });
20965
21311
  }
20966
- //#endregion
20967
- //#region src/components/TasksTab.tsx
21312
+ // src/components/TasksTab.tsx
20968
21313
  const STATUS_STYLE = {
20969
21314
  working: {
20970
21315
  glyph: "◐",
@@ -21316,8 +21661,7 @@ function subscribableResources(resources, subscriptions) {
21316
21661
  }
21317
21662
  return rows;
21318
21663
  }
21319
- //#endregion
21320
- //#region src/components/SubscriptionsTab.tsx
21664
+ // src/components/SubscriptionsTab.tsx
21321
21665
  const STREAM_STATUS_TEXT = {
21322
21666
  connecting: {
21323
21667
  text: "connecting…",
@@ -21597,8 +21941,7 @@ function SubscriptionsTab({ resources, subscriptions, streamState, messages, ins
21597
21941
  })]
21598
21942
  });
21599
21943
  }
21600
- //#endregion
21601
- //#region src/components/RootsModal.tsx
21944
+ // src/components/RootsModal.tsx
21602
21945
  const ADD_ROOT_FORM = {
21603
21946
  title: "Add Root",
21604
21947
  sections: [{
@@ -21624,7 +21967,7 @@ function rootFromForm(values) {
21624
21967
  name
21625
21968
  } : { uri };
21626
21969
  }
21627
- function RootsModal({ roots, inspectorClient, connected, width, height, onClose }) {
21970
+ function RootsModal({ roots, inspectorClient, connected, width, height, onClose, inputActive = true }) {
21628
21971
  const [mode, setMode] = useState("list");
21629
21972
  const [error, setError] = useState(null);
21630
21973
  const [saving, setSaving] = useState(false);
@@ -21649,6 +21992,7 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
21649
21992
  }
21650
21993
  };
21651
21994
  const handleSubmit = (values) => {
21995
+ if (!inputActive) return;
21652
21996
  const root = rootFromForm(values);
21653
21997
  if ("error" in root) {
21654
21998
  setError(root.error);
@@ -21680,7 +22024,7 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
21680
22024
  }
21681
22025
  save(roots.filter((_, i) => i !== selectedIndex));
21682
22026
  }
21683
- });
22027
+ }, { isActive: inputActive });
21684
22028
  return /* @__PURE__ */ jsx(Box, {
21685
22029
  position: "absolute",
21686
22030
  width,
@@ -21791,8 +22135,468 @@ function RootsModal({ roots, inspectorClient, connected, width, height, onClose
21791
22135
  })
21792
22136
  });
21793
22137
  }
21794
- //#endregion
21795
- //#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
21796
22600
  const APP_NAME = "MCP Inspector TUI";
21797
22601
  const APP_DESCRIPTION = "Terminal User Interface for the Model Context Protocol Inspector";
21798
22602
  const APP_VERSION = readInspectorVersion(import.meta.url);
@@ -21809,7 +22613,6 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21809
22613
  const [activeTab, setActiveTab] = useState("info");
21810
22614
  const [paneFocus, setFocus] = useState("serverList");
21811
22615
  const [helpOpen, setHelpOpen] = useState(false);
21812
- const focus = helpOpen ? "help" : paneFocus;
21813
22616
  const [listFilterEditing, setListFilterEditing] = useState(false);
21814
22617
  const [listFilterClaimsEscape, setListFilterClaimsEscape] = useState(false);
21815
22618
  const [tabCounts, setTabCounts] = useState({});
@@ -21912,6 +22715,11 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
21912
22715
  ...defaultMetadata && Object.keys(defaultMetadata).length > 0 && { defaultMetadata },
21913
22716
  ...savedSettings && { serverSettings: savedSettings },
21914
22717
  roots: cleanRoots(savedSettings?.roots ?? []),
22718
+ sample: true,
22719
+ elicit: {
22720
+ form: true,
22721
+ url: true
22722
+ },
21915
22723
  ...savedSettings?.protocolEra && { versionNegotiation: eraToVersionNegotiation(savedSettings.protocolEra) },
21916
22724
  ...clientAuthOptions
21917
22725
  };
@@ -22067,6 +22875,9 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22067
22875
  if (activeTab === "auth" && selectedServerConfig && !isOAuthCapableServerConfig(selectedServerConfig)) setActiveTab("info");
22068
22876
  }, [activeTab, selectedServerConfig]);
22069
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;
22070
22881
  const { status: inspectorStatus, capabilities: inspectorCapabilities, serverInfo: inspectorServerInfo, instructions: inspectorInstructions, connect: connectInspector, disconnect: disconnectInspector, lastError: inspectorLastError } = useInspectorClient(selectedInspectorClient);
22071
22882
  const selectedMessageLogState = useMemo(() => selectedServer && messageLogStates[selectedServer] ? messageLogStates[selectedServer] : null, [selectedServer, messageLogStates]);
22072
22883
  const selectedFetchRequestLogState = useMemo(() => selectedServer && fetchRequestLogStates[selectedServer] ? fetchRequestLogStates[selectedServer] : null, [selectedServer, fetchRequestLogStates]);
@@ -22776,7 +23587,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
22776
23587
  inspectorClients
22777
23588
  ]);
22778
23589
  useInput((input, key) => {
22779
- if (toolTestModal || resourceTestModal || promptTestModal || detailsModal || helpOpen || rootsModalOpen) return;
23590
+ if (toolTestModal || resourceTestModal || promptTestModal || detailsModal || helpOpen || rootsModalOpen || pendingRequestOpen) return;
22780
23591
  if (key.ctrl && input === "c") exit();
22781
23592
  if (listFilterEditing) return;
22782
23593
  if (input === "?") {
@@ -23403,6 +24214,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23403
24214
  width: dimensions.width,
23404
24215
  height: dimensions.height,
23405
24216
  onClose: () => setToolTestModal(null),
24217
+ inputActive: !pendingRequestOpen,
23406
24218
  onAuthRecoveryRequired: (error) => {
23407
24219
  onAuthRecoveryRequired(error);
23408
24220
  setToolTestModal(null);
@@ -23414,6 +24226,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23414
24226
  width: dimensions.width,
23415
24227
  height: dimensions.height,
23416
24228
  onClose: () => setResourceTestModal(null),
24229
+ inputActive: !pendingRequestOpen,
23417
24230
  onAuthRecoveryRequired: (error) => {
23418
24231
  onAuthRecoveryRequired(error);
23419
24232
  setResourceTestModal(null);
@@ -23425,6 +24238,7 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23425
24238
  width: dimensions.width,
23426
24239
  height: dimensions.height,
23427
24240
  onClose: () => setPromptTestModal(null),
24241
+ inputActive: !pendingRequestOpen,
23428
24242
  onAuthRecoveryRequired: (error) => {
23429
24243
  onAuthRecoveryRequired(error);
23430
24244
  setPromptTestModal(null);
@@ -23434,7 +24248,8 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23434
24248
  sections: keybindingSections(activeTab, shownTabs),
23435
24249
  width: dimensions.width,
23436
24250
  height: dimensions.height,
23437
- onClose: () => setHelpOpen(false)
24251
+ onClose: () => setHelpOpen(false),
24252
+ inputActive: !pendingRequestOpen
23438
24253
  }),
23439
24254
  rootsModalOpen && /* @__PURE__ */ jsx(RootsModal, {
23440
24255
  roots: advertisedRoots,
@@ -23442,7 +24257,8 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23442
24257
  connected: inspectorStatus === "connected",
23443
24258
  width: dimensions.width,
23444
24259
  height: dimensions.height,
23445
- onClose: () => setRootsModalOpen(false)
24260
+ onClose: () => setRootsModalOpen(false),
24261
+ inputActive: !pendingRequestOpen
23446
24262
  }),
23447
24263
  detailsModal && !helpOpen && /* @__PURE__ */ jsx(DetailsModal, {
23448
24264
  title: detailsModal.title,
@@ -23450,13 +24266,20 @@ function App({ mcpServers, clientConfig, clientId, clientSecret, clientMetadataU
23450
24266
  width: dimensions.width,
23451
24267
  height: dimensions.height,
23452
24268
  onClose: () => setDetailsModal(null),
23453
- 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
23454
24278
  })
23455
24279
  ]
23456
24280
  });
23457
24281
  }
23458
- //#endregion
23459
- //#region tui.tsx
24282
+ // tui.tsx
23460
24283
  async function runTui(args) {
23461
24284
  const program = new Command();
23462
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);
@@ -23511,8 +24334,7 @@ async function runTui(args) {
23511
24334
  process.exit(1);
23512
24335
  }
23513
24336
  }
23514
- //#endregion
23515
- //#region index.ts
24337
+ // index.ts
23516
24338
  const __filename = fileURLToPath(import.meta.url);
23517
24339
  if (process.argv[1] !== void 0 && resolve(process.argv[1]) === resolve(__filename)) runTui(process.argv).catch((err) => {
23518
24340
  console.error("Error:", err instanceof Error ? err.message : err);
@@ -23523,5 +24345,4 @@ if (process.argv[1] !== void 0 && resolve(process.argv[1]) === resolve(__filenam
23523
24345
  if ((debugOn(process.env.MCP_DEBUG) || debugOn(process.env.DEBUG)) && err instanceof Error) console.error(err.stack);
23524
24346
  process.exit(1);
23525
24347
  });
23526
- //#endregion
23527
24348
  export { runTui };