@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.
@@ -37,20 +37,18 @@ import { createServer as createServer$2 } from "node:https";
37
37
  import { serve } from "@hono/node-server";
38
38
  import { serveStatic } from "@hono/node-server/serve-static";
39
39
  import { spawnSync } from "node:child_process";
40
- //#region ../../core/storage/store-id.ts
40
+ // ../../core/storage/store-id.ts
41
41
  function validateStoreId(storeId) {
42
42
  return /^[a-zA-Z0-9_-]+$/.test(storeId) && storeId !== "__proto__";
43
43
  }
44
- //#endregion
45
- //#region ../../core/storage/store-serialize.ts
44
+ // ../../core/storage/store-serialize.ts
46
45
  function serializeStore(data) {
47
46
  return JSON.stringify(data, null, 2);
48
47
  }
49
48
  function parseStore(raw) {
50
49
  return JSON.parse(raw);
51
50
  }
52
- //#endregion
53
- //#region ../../core/storage/store-io.ts
51
+ // ../../core/storage/store-io.ts
54
52
  function getDefaultStorageDir() {
55
53
  const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
56
54
  return path$1.join(homeDir, ".mcp-inspector", "storage");
@@ -96,8 +94,7 @@ async function deleteStoreFile(filePath) {
96
94
  if (error.code !== "ENOENT") throw error;
97
95
  }
98
96
  }
99
- //#endregion
100
- //#region ../../core/mcp/types.ts
97
+ // ../../core/mcp/types.ts
101
98
  const DEFAULT_TASK_TTL_MS = 6e4;
102
99
  const DEFAULT_MAX_FETCH_REQUESTS = 1e3;
103
100
  const MODERN_LOG_LEVELS = [
@@ -114,8 +111,7 @@ const MODERN_LOG_LEVELS = [
114
111
  function isModernLogLevel(value) {
115
112
  return typeof value === "string" && MODERN_LOG_LEVELS.includes(value);
116
113
  }
117
- //#endregion
118
- //#region ../../core/extension/skills/schemas.ts
114
+ // ../../core/extension/skills/schemas.ts
119
115
  const CACHE_FIELDS = {
120
116
  ttlMs: ReadResourceDirectoryResultSchema.shape.ttlMs,
121
117
  cacheScope: SkillCacheScopeSchema
@@ -227,13 +223,11 @@ SKILL_LIMITS.bytes;
227
223
  function isSkillCatalogLimit(value) {
228
224
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
229
225
  }
230
- //#endregion
231
- //#region ../../core/auth/secret-fields.ts
226
+ // ../../core/auth/secret-fields.ts
232
227
  const SECRET_FIELD_OAUTH_CLIENT_SECRET = "oauth-client-secret";
233
228
  const SECRET_FIELD_IDP_CLIENT_SECRET = "idp-client-secret";
234
229
  const envSecretField = (envKey) => `env:${envKey}`;
235
- //#endregion
236
- //#region ../../core/json/jsonUtils.ts
230
+ // ../../core/json/jsonUtils.ts
237
231
  function isSerializableJson(value) {
238
232
  if (value === null) return true;
239
233
  switch (typeof value) {
@@ -247,8 +241,7 @@ function isSerializableJson(value) {
247
241
  function toRecord(value) {
248
242
  return value;
249
243
  }
250
- //#endregion
251
- //#region ../../core/mcp/serverList.ts
244
+ // ../../core/mcp/serverList.ts
252
245
  const VALID_SERVER_TYPES = /* @__PURE__ */ new Set([
253
246
  "stdio",
254
247
  "sse",
@@ -587,8 +580,7 @@ function defaultSeedConfig(tempDir) {
587
580
  }
588
581
  } };
589
582
  }
590
- //#endregion
591
- //#region ../../core/storage/own-entry.ts
583
+ // ../../core/storage/own-entry.ts
592
584
  function setOwnEntry(map, key, value) {
593
585
  Object.defineProperty(map, key, {
594
586
  value,
@@ -600,8 +592,7 @@ function setOwnEntry(map, key, value) {
600
592
  function getOwnEntry(map, key) {
601
593
  return map !== void 0 && Object.hasOwn(map, key) ? map[key] : void 0;
602
594
  }
603
- //#endregion
604
- //#region ../../core/mcp/node/config.ts
595
+ // ../../core/mcp/node/config.ts
605
596
  function parseKeyValuePair(value, previous = {}) {
606
597
  const parts = value.split("=");
607
598
  const key = parts[0] ?? "";
@@ -770,8 +761,7 @@ function resolveServerConfigs(options, mode) {
770
761
  }
771
762
  const API_SERVER_ENV_VARS = { AUTH_TOKEN: "MCP_INSPECTOR_API_TOKEN" };
772
763
  const INSPECTOR_API_TOKEN_GLOBAL = "__INSPECTOR_API_TOKEN__";
773
- //#endregion
774
- //#region ../../core/auth/secret-storage-info.ts
764
+ // ../../core/auth/secret-storage-info.ts
775
765
  function secretStorageLabel(info) {
776
766
  switch (info.kind) {
777
767
  case "keyring": return "OS keychain";
@@ -798,8 +788,7 @@ function secretStorageSummary(info) {
798
788
  if (info.reason === "fallback") parts.push("— fell back from the OS keychain");
799
789
  return parts.join(" ");
800
790
  }
801
- //#endregion
802
- //#region ../../core/node/version.ts
791
+ // ../../core/node/version.ts
803
792
  const ROOT_PACKAGE_NAME = "@modelcontextprotocol/inspector";
804
793
  function readInspectorVersion(callerUrl) {
805
794
  const startDir = dirname(fileURLToPath(callerUrl));
@@ -823,8 +812,7 @@ function readInspectorVersionSafe(callerUrl) {
823
812
  return;
824
813
  }
825
814
  }
826
- //#endregion
827
- //#region ../../core/node/openUrl.ts
815
+ // ../../core/node/openUrl.ts
828
816
  const OPEN_URL_TIMEOUT_MS = 5e3;
829
817
  const OPENABLE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
830
818
  function toOpenableHref(href) {
@@ -852,8 +840,7 @@ async function openUrl(url, timeoutMs = OPEN_URL_TIMEOUT_MS) {
852
840
  clearTimeout(timer);
853
841
  }
854
842
  }
855
- //#endregion
856
- //#region ../../core/node/hostUrl.ts
843
+ // ../../core/node/hostUrl.ts
857
844
  function stripBrackets(host) {
858
845
  return host.replace(/^\[(.*)\]$/, "$1");
859
846
  }
@@ -906,8 +893,7 @@ function isLoopbackHost(host) {
906
893
  const h = canonicalUrlHost(host).replace(/\.$/, "");
907
894
  return h === "localhost" || h === "[::1]" || /^127(\.(25[0-5]|2[0-4]\d|1?\d?\d)){3}$/.test(h);
908
895
  }
909
- //#endregion
910
- //#region server/resolve-bind-host.ts
896
+ // server/resolve-bind-host.ts
911
897
  const BIND_ALL_INTERFACES_ENV = "DANGEROUSLY_BIND_ALL_INTERFACES";
912
898
  function isEnvFlagEnabled(value) {
913
899
  const v = value?.trim().toLowerCase();
@@ -923,8 +909,7 @@ function resolveBindHostname(env = process.env) {
923
909
  }
924
910
  return stripBrackets(host);
925
911
  }
926
- //#endregion
927
- //#region server/host-allow-list.ts
912
+ // server/host-allow-list.ts
928
913
  const ALLOWED_HOSTS_ENV = "MCP_INSPECTOR_ALLOWED_HOSTS";
929
914
  const HOSTNAME_RE = /^[a-z0-9._-]+$/;
930
915
  function normalizeHostname(hostname) {
@@ -1006,8 +991,7 @@ function hostAllowListMiddleware(options) {
1006
991
  await next();
1007
992
  };
1008
993
  }
1009
- //#endregion
1010
- //#region server/sandbox-controller.ts
994
+ // server/sandbox-controller.ts
1011
995
  const __dirname$3 = dirname(fileURLToPath(import.meta.url));
1012
996
  function isSandboxPath(url) {
1013
997
  const path = (url ?? "").split("?", 1)[0];
@@ -1328,8 +1312,7 @@ function createAppOriginController(options) {
1328
1312
  }
1329
1313
  };
1330
1314
  }
1331
- //#endregion
1332
- //#region server/public-address.ts
1315
+ // server/public-address.ts
1333
1316
  const SANDBOX_FULL_ADDRESS_ENV = "MCP_SANDBOX_FULL_ADDRESS";
1334
1317
  const APP_ORIGIN_FULL_ADDRESS_ENV = "MCP_APP_ORIGIN_FULL_ADDRESS";
1335
1318
  const SANDBOX_PATH = "/sandbox";
@@ -1398,8 +1381,7 @@ function resolveAppOriginPublicOrigin(raw, allowedOrigins, sandboxUrl) {
1398
1381
  warnMixedContent(APP_ORIGIN_FULL_ADDRESS_ENV, url, allowedOrigins);
1399
1382
  return url.origin;
1400
1383
  }
1401
- //#endregion
1402
- //#region server/tls.ts
1384
+ // server/tls.ts
1403
1385
  const TLS_KEY_PATH_ENV = "INSPECTOR_TLS_KEY_PATH";
1404
1386
  const TLS_CERT_PATH_ENV = "INSPECTOR_TLS_CERT_PATH";
1405
1387
  function webScheme(tls) {
@@ -1435,8 +1417,7 @@ function resolveTlsConfig(env = process.env) {
1435
1417
  cert
1436
1418
  };
1437
1419
  }
1438
- //#endregion
1439
- //#region server/web-server-config.ts
1420
+ // server/web-server-config.ts
1440
1421
  const inspectorVersion = readInspectorVersionSafe(import.meta.url);
1441
1422
  function defaultEnvironmentFromProcess(extra) {
1442
1423
  const keys = process.platform === "win32" ? [
@@ -1625,8 +1606,7 @@ function resolveAutoOpen() {
1625
1606
  if (flag === "false") return false;
1626
1607
  return !process.env.VITEST;
1627
1608
  }
1628
- //#endregion
1629
- //#region ../../core/mcp/config.ts
1609
+ // ../../core/mcp/config.ts
1630
1610
  function getServerType(config) {
1631
1611
  if (!("type" in config) || config.type === void 0) return "stdio";
1632
1612
  const type = config.type;
@@ -1635,8 +1615,7 @@ function getServerType(config) {
1635
1615
  if (type === "streamable-http") return "streamable-http";
1636
1616
  throw new Error(`Invalid server type: ${type}. Valid types are: stdio, sse, streamable-http`);
1637
1617
  }
1638
- //#endregion
1639
- //#region ../../core/mcp/fetchTracking.ts
1618
+ // ../../core/mcp/fetchTracking.ts
1640
1619
  const SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
1641
1620
  "authorization",
1642
1621
  "cookie",
@@ -1745,14 +1724,15 @@ function isLongLivedStreamResponse(method, contentType) {
1745
1724
  }
1746
1725
  const CHALLENGE_BODY_MAX_BYTES = 65536;
1747
1726
  const CHALLENGE_BODY_READ_MS = 2e3;
1727
+ const TRACKED_BODY_MAX_BYTES = 1048576;
1748
1728
  const TRUNCATED_BODY_SUFFIX = "\n[truncated]";
1749
1729
  const WITHHELD_TRUNCATED_JSON_BODY = "[truncated JSON body withheld: an incomplete body cannot be redacted]";
1750
- function recordableChallengeBody(read, contentType) {
1730
+ function recordableBody(read, contentType) {
1751
1731
  if (!read.truncated) return redactBody(read.text, contentType);
1752
1732
  if ((contentType ?? "").toLowerCase().includes("json") || /^\s*[{[]/.test(read.text)) return WITHHELD_TRUNCATED_JSON_BODY;
1753
1733
  return redactBody(read.text, contentType) + TRUNCATED_BODY_SUFFIX;
1754
1734
  }
1755
- async function readChallengeBody(response) {
1735
+ async function readCappedBody(response, maxBytes, timeoutMs) {
1756
1736
  let reader;
1757
1737
  try {
1758
1738
  const body = response.clone().body;
@@ -1766,20 +1746,23 @@ async function readChallengeBody(response) {
1766
1746
  let text = "";
1767
1747
  let bytes = 0;
1768
1748
  let timer;
1769
- const deadline = new Promise((resolve) => {
1770
- timer = setTimeout(() => resolve("timeout"), CHALLENGE_BODY_READ_MS);
1749
+ const deadline = timeoutMs === void 0 ? void 0 : new Promise((resolve) => {
1750
+ timer = setTimeout(() => resolve("timeout"), timeoutMs);
1771
1751
  });
1772
1752
  try {
1773
- while (bytes < CHALLENGE_BODY_MAX_BYTES) {
1774
- const next = await Promise.race([reader.read(), deadline]);
1753
+ for (;;) {
1754
+ const next = await (deadline ? Promise.race([reader.read(), deadline]) : reader.read());
1775
1755
  if (next === "timeout") break;
1776
1756
  if (next.done) return {
1777
1757
  text: text + decoder.decode(),
1778
1758
  truncated: false
1779
1759
  };
1780
- const chunk = next.value.subarray(0, CHALLENGE_BODY_MAX_BYTES - bytes);
1760
+ if (next.value.byteLength === 0) continue;
1761
+ if (bytes >= maxBytes) break;
1762
+ const chunk = next.value.subarray(0, maxBytes - bytes);
1781
1763
  bytes += chunk.byteLength;
1782
1764
  text += decoder.decode(chunk, { stream: true });
1765
+ if (chunk.byteLength < next.value.byteLength) break;
1783
1766
  }
1784
1767
  reader.cancel().catch(() => {});
1785
1768
  return {
@@ -1792,6 +1775,9 @@ async function readChallengeBody(response) {
1792
1775
  clearTimeout(timer);
1793
1776
  }
1794
1777
  }
1778
+ function readChallengeBody(response) {
1779
+ return readCappedBody(response, CHALLENGE_BODY_MAX_BYTES, CHALLENGE_BODY_READ_MS);
1780
+ }
1795
1781
  function longLivedStreamFraming(contentType) {
1796
1782
  return contentType?.toLowerCase().includes("application/x-ndjson") ? "ndjson" : "sse";
1797
1783
  }
@@ -1957,7 +1943,7 @@ function createFetchTracker(baseFetch, callbacks) {
1957
1943
  };
1958
1944
  if ((responseStatus === 401 || responseStatus === 403) && response.body && !response.bodyUsed) {
1959
1945
  const read = await readChallengeBody(response);
1960
- entry.responseBody = read === void 0 ? void 0 : recordableChallengeBody(read, response.headers.get("content-type"));
1946
+ entry.responseBody = read === void 0 ? void 0 : recordableBody(read, response.headers.get("content-type"));
1961
1947
  callbacks.trackRequest?.(entry);
1962
1948
  return response;
1963
1949
  }
@@ -1965,11 +1951,12 @@ function createFetchTracker(baseFetch, callbacks) {
1965
1951
  if (isLongLivedStream && response.body && !response.bodyUsed) watchLongLivedStream(response, id, longLivedStreamFraming(response.headers.get("content-type")), callbacks);
1966
1952
  if (!isLongLivedStream && response.body && !response.bodyUsed) {
1967
1953
  const responseContentType = response.headers.get("content-type");
1968
- try {
1969
- response.clone().text().then((body) => {
1970
- callbacks.updateResponseBody?.(id, redactBody(body, responseContentType) ?? body);
1971
- }).catch(() => {});
1972
- } catch {}
1954
+ readCappedBody(response, TRACKED_BODY_MAX_BYTES).then((read) => {
1955
+ if (read === void 0) return;
1956
+ try {
1957
+ callbacks.updateResponseBody?.(id, recordableBody(read, responseContentType));
1958
+ } catch {}
1959
+ });
1973
1960
  }
1974
1961
  return response;
1975
1962
  };
@@ -2035,8 +2022,7 @@ function parseAuthChallengeFromResponse(response, context) {
2035
2022
  }
2036
2023
  };
2037
2024
  }
2038
- //#endregion
2039
- //#region ../../core/mcp/node/authChallengeFetch.ts
2025
+ // ../../core/mcp/node/authChallengeFetch.ts
2040
2026
  function createAuthChallengeInterceptFetch(baseFetch) {
2041
2027
  return async (input, init) => {
2042
2028
  const response = await baseFetch(input, init);
@@ -2057,8 +2043,7 @@ function createAuthChallengeObserverFetch(baseFetch, onChallenge) {
2057
2043
  return response;
2058
2044
  };
2059
2045
  }
2060
- //#endregion
2061
- //#region ../../core/mcp/node/proxyFetch.ts
2046
+ // ../../core/mcp/node/proxyFetch.ts
2062
2047
  function asUndiciInit(init) {
2063
2048
  return init;
2064
2049
  }
@@ -2148,8 +2133,7 @@ function createProxyFetch() {
2148
2133
  return (await loadedProxiedFetch)(input, init);
2149
2134
  };
2150
2135
  }
2151
- //#endregion
2152
- //#region ../../core/auth/requestTimeout.ts
2136
+ // ../../core/auth/requestTimeout.ts
2153
2137
  const OAUTH_TIMEOUT_WIRE_CODE = "oauth_request_timeout";
2154
2138
  function readNegotiatesEndpoint(hint) {
2155
2139
  if (!hint) return true;
@@ -2196,11 +2180,23 @@ function callerSignalOf(input, init) {
2196
2180
  if (explicit !== void 0) return explicit ?? void 0;
2197
2181
  if (typeof input !== "string" && !(input instanceof URL)) return input.signal;
2198
2182
  }
2199
- //#endregion
2200
- //#region ../../core/mcp/node/fetchGuard.ts
2183
+ // ../../core/auth/fetchRefusal.ts
2201
2184
  var FetchTargetError = class extends Error {
2202
2185
  name = "FetchTargetError";
2186
+ url;
2187
+ constructor(message, url) {
2188
+ super(message);
2189
+ if (url !== void 0) this.url = url;
2190
+ }
2203
2191
  };
2192
+ function findFetchTargetError(err) {
2193
+ let current = err;
2194
+ for (let depth = 0; depth < 8 && current instanceof Error; depth++) {
2195
+ if (current instanceof FetchTargetError) return current;
2196
+ current = current.cause;
2197
+ }
2198
+ }
2199
+ const FETCH_TARGET_REFUSED_WIRE_CODE = "fetch_target_refused";
2204
2200
  const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
2205
2201
  301,
2206
2202
  302,
@@ -2209,11 +2205,12 @@ const REDIRECT_STATUSES = /* @__PURE__ */ new Set([
2209
2205
  308
2210
2206
  ]);
2211
2207
  const resolveWithSystemDns = async (hostname) => (await lookup(hostname, { all: true })).map((r) => r.address);
2208
+ const METADATA_IPV4_ADDRESSES = /* @__PURE__ */ new Set(["100.100.100.200", "192.0.0.192"]);
2212
2209
  function isBlockedAddress(ip) {
2213
2210
  const kind = isIP(ip);
2214
2211
  if (kind === 4) {
2215
2212
  const [a, b] = ip.split(".").map(Number);
2216
- return a === 169 && b === 254;
2213
+ return a === 169 && b === 254 || METADATA_IPV4_ADDRESSES.has(ip);
2217
2214
  }
2218
2215
  if (kind !== 6) return false;
2219
2216
  const addr = ip.toLowerCase();
@@ -2376,27 +2373,35 @@ async function guardedFetch(url, init, options = {}) {
2376
2373
  headers: init.headers
2377
2374
  };
2378
2375
  for (let hop = 0; hop <= 5; hop++) {
2379
- await assertAllowedTarget(request.url, resolveHost, viaProxy, init.signal);
2380
- const res = await fetchFn(request.url.href, {
2381
- method: request.method,
2382
- headers: new Headers(request.headers),
2383
- body: request.body,
2384
- signal: init.signal,
2385
- redirect: "manual"
2386
- });
2376
+ let res;
2377
+ try {
2378
+ await assertAllowedTarget(request.url, resolveHost, viaProxy, init.signal);
2379
+ res = await fetchFn(request.url.href, {
2380
+ method: request.method,
2381
+ headers: new Headers(request.headers),
2382
+ body: request.body,
2383
+ signal: init.signal,
2384
+ redirect: "manual"
2385
+ });
2386
+ } catch (err) {
2387
+ stampRefusedUrl(err, request.url);
2388
+ throw err;
2389
+ }
2387
2390
  const location = res.headers.get("location");
2388
2391
  if (!REDIRECT_STATUSES.has(res.status) || location === null) return res;
2389
2392
  res.body?.cancel().catch(() => {});
2390
- request = nextRedirectRequest(request, res.status, location);
2393
+ try {
2394
+ request = nextRedirectRequest(request, res.status, location);
2395
+ } catch (err) {
2396
+ stampRefusedUrl(err, request.url);
2397
+ throw err;
2398
+ }
2391
2399
  }
2392
- throw new FetchTargetError(`Refusing to follow more than 5 redirects`);
2400
+ throw new FetchTargetError(`Refusing to follow more than 5 redirects`, request.url.href);
2393
2401
  }
2394
- function findFetchTargetError(err) {
2395
- let current = err;
2396
- for (let depth = 0; depth < 8 && current instanceof Error; depth++) {
2397
- if (current instanceof FetchTargetError) return current;
2398
- current = current.cause;
2399
- }
2402
+ function stampRefusedUrl(err, url) {
2403
+ const refused = findFetchTargetError(err);
2404
+ if (refused && refused.url === void 0) refused.url = url.href;
2400
2405
  }
2401
2406
  async function bodyText(input, init) {
2402
2407
  const body = init?.body !== void 0 ? init.body : input instanceof Request && input.body !== null ? await input.clone().text() : void 0;
@@ -2423,8 +2428,7 @@ function createGuardedFetch(options = {}) {
2423
2428
  }
2424
2429
  };
2425
2430
  }
2426
- //#endregion
2427
- //#region ../../core/auth/routeOAuthRequests.ts
2431
+ // ../../core/auth/routeOAuthRequests.ts
2428
2432
  function isJsonRpcMessage(value) {
2429
2433
  return typeof value === "object" && value !== null && value.jsonrpc === "2.0";
2430
2434
  }
@@ -2448,8 +2452,7 @@ function isMcpShapedRequest(input, init) {
2448
2452
  function routeOAuthRequests(mcpFetch, oauthFetch, isMcpEndpoint) {
2449
2453
  return (input, init) => isMcpShapedRequest(input, init) && isMcpEndpoint(requestUrlOf(input), requestHeadersOf(input, init)) ? mcpFetch(input, init) : oauthFetch(input, init);
2450
2454
  }
2451
- //#endregion
2452
- //#region ../../core/mcp/node/notificationHeadersFetch.ts
2455
+ // ../../core/mcp/node/notificationHeadersFetch.ts
2453
2456
  function createNotificationHeadersFetch(baseFetch) {
2454
2457
  return (input, init) => {
2455
2458
  const method = modernNotificationMethod(init);
@@ -2485,8 +2488,7 @@ function modernNotificationMethod(init) {
2485
2488
  function isRecord$2(value) {
2486
2489
  return typeof value === "object" && value !== null && !Array.isArray(value);
2487
2490
  }
2488
- //#endregion
2489
- //#region ../../core/mcp/node/suppressNotificationStreamFetch.ts
2491
+ // ../../core/mcp/node/suppressNotificationStreamFetch.ts
2490
2492
  function createSuppressNotificationStreamFetch(baseFetch, endpoint) {
2491
2493
  return async (input, init) => {
2492
2494
  if (isStandaloneStreamRequest(input, init, endpoint)) return new Response(null, {
@@ -2512,8 +2514,7 @@ function isStandaloneStreamRequest(input, init, endpoint) {
2512
2514
  const headers = new Headers(init?.headers ?? request?.headers);
2513
2515
  return (headers.get("accept")?.toLowerCase() ?? "").includes("text/event-stream") && !headers.has("last-event-id");
2514
2516
  }
2515
- //#endregion
2516
- //#region ../../core/mcp/node/transport.ts
2517
+ // ../../core/mcp/node/transport.ts
2517
2518
  function headersFromSettings(settings) {
2518
2519
  if (!settings || settings.headers.length === 0) return void 0;
2519
2520
  const out = {};
@@ -2595,8 +2596,7 @@ function createTransportNode(config, options = {}) {
2595
2596
  }) };
2596
2597
  }
2597
2598
  }
2598
- //#endregion
2599
- //#region ../../core/mcp/remote/node/cappedBody.ts
2599
+ // ../../core/mcp/remote/node/cappedBody.ts
2600
2600
  async function readCappedText(body, maxBytes) {
2601
2601
  const reader = body.getReader();
2602
2602
  const decoder = new TextDecoder();
@@ -2665,6 +2665,24 @@ var RateLimitLedger = class {
2665
2665
  function isRateLimitError(err) {
2666
2666
  return SdkHttpError.isInstance(err) && err.status === 429;
2667
2667
  }
2668
+ // ../../core/mcp/sessionTermination.ts
2669
+ function canTerminateSession(transport) {
2670
+ return typeof transport === "object" && transport !== null && "terminateSession" in transport && typeof transport.terminateSession === "function";
2671
+ }
2672
+ const SESSION_TERMINATE_TIMEOUT_MS = 3e3;
2673
+ async function terminateSessionBestEffort(transport, timeoutMs = SESSION_TERMINATE_TIMEOUT_MS) {
2674
+ if (!canTerminateSession(transport) || !transport.sessionId) return false;
2675
+ let timer;
2676
+ const timedOut = new Promise((resolve) => {
2677
+ timer = setTimeout(() => resolve(false), timeoutMs);
2678
+ });
2679
+ const terminated = new Promise((resolve) => resolve(transport.terminateSession())).then(() => true, () => false);
2680
+ try {
2681
+ return await Promise.race([terminated, timedOut]);
2682
+ } finally {
2683
+ clearTimeout(timer);
2684
+ }
2685
+ }
2668
2686
  function mergeOAuthSections(disk, snapshot, sections) {
2669
2687
  const merged = {
2670
2688
  servers: { ...disk?.servers },
@@ -2781,8 +2799,7 @@ function parseOAuthStoreWriteBody(body) {
2781
2799
  if (!snapshot || !snapshotHasValidSecretPayloads(snapshot)) return null;
2782
2800
  return { snapshot };
2783
2801
  }
2784
- //#endregion
2785
- //#region ../../core/auth/node/secret-store.ts
2802
+ // ../../core/auth/node/secret-store.ts
2786
2803
  const SERVICE_NAME = "mcp-inspector";
2787
2804
  let keyringLoad;
2788
2805
  var KeyringModuleShapeError = class extends Error {
@@ -3002,8 +3019,7 @@ var SessionSecretStore = class extends InMemorySecretStore {
3002
3019
  return false;
3003
3020
  }
3004
3021
  };
3005
- //#endregion
3006
- //#region ../../core/auth/node/file-lock.ts
3022
+ // ../../core/auth/node/file-lock.ts
3007
3023
  const STALE_MS = 1e4;
3008
3024
  const RETRY = {
3009
3025
  retries: 20,
@@ -3135,8 +3151,7 @@ async function withSecretFileLock(filePath, fn) {
3135
3151
  await release();
3136
3152
  }
3137
3153
  }
3138
- //#endregion
3139
- //#region ../../core/auth/node/file-secret-store.ts
3154
+ // ../../core/auth/node/file-secret-store.ts
3140
3155
  const scrypt = (passphrase, salt, keylen, options) => new Promise((resolve, reject) => {
3141
3156
  crypto$1.scrypt(passphrase, salt, keylen, options, (err, key) => {
3142
3157
  /* v8 ignore next -- @preserve: node validates the cost parameters
@@ -3544,8 +3559,7 @@ async function readSecretFilePermissions(filePath) {
3544
3559
  };
3545
3560
  }
3546
3561
  }
3547
- //#endregion
3548
- //#region ../../core/auth/node/secret-store-selection.ts
3562
+ // ../../core/auth/node/secret-store-selection.ts
3549
3563
  const SECRET_STORE_ENV = "MCP_INSPECTOR_SECRET_STORE";
3550
3564
  const SECRET_FILE_ENV = "MCP_INSPECTOR_SECRET_FILE";
3551
3565
  const STORAGE_DIR_ENV = "MCP_STORAGE_DIR";
@@ -3857,8 +3871,7 @@ function defaultSecretStore() {
3857
3871
  async function resolveConcreteSecretStore(store) {
3858
3872
  return store instanceof DeferredSecretStore ? (await resolveSecretStore()).store : store;
3859
3873
  }
3860
- //#endregion
3861
- //#region ../../core/auth/node/oauth-secrets.ts
3874
+ // ../../core/auth/node/oauth-secrets.ts
3862
3875
  const PERSIST_TOKENS_ENV = "MCP_INSPECTOR_PERSIST_TOKENS";
3863
3876
  const warnedPolicyValues = /* @__PURE__ */ new Set();
3864
3877
  function getPersistTokensPolicy(env = process.env) {
@@ -4128,8 +4141,7 @@ function snapshotHasPlaintextSecrets(snapshot) {
4128
4141
  for (const session of Object.values(snapshot.idpSessions)) if (session.idToken !== void 0 || session.refreshToken !== void 0) return true;
4129
4142
  return false;
4130
4143
  }
4131
- //#endregion
4132
- //#region ../../core/auth/node/oauth-namespace-ledger.ts
4144
+ // ../../core/auth/node/oauth-namespace-ledger.ts
4133
4145
  const namespaceLedgerPath = (stateFilePath) => `${stateFilePath}.namespaces.json`;
4134
4146
  const KEYRING_LOCATION = "keyring";
4135
4147
  const FILE_LOCATION_PREFIX = "file:";
@@ -4387,8 +4399,7 @@ async function purgeSupersededNamespaces(stateFilePath, secretStore, current, ow
4387
4399
  warnLedgerFailure("update", error);
4388
4400
  }
4389
4401
  }
4390
- //#endregion
4391
- //#region ../../core/auth/node/oauth-persist-file.ts
4402
+ // ../../core/auth/node/oauth-persist-file.ts
4392
4403
  const warnedStoreFailures = /* @__PURE__ */ new Set();
4393
4404
  function warnStoreWriteFailure(error) {
4394
4405
  const reason = error instanceof Error ? error.message : String(error);
@@ -4920,8 +4931,7 @@ async function removeOAuthStore(filePath, secretStore = defaultSecretStore()) {
4920
4931
  if (locked) await purgeSupersededNamespaces(filePath, secretStore, void 0);
4921
4932
  });
4922
4933
  }
4923
- //#endregion
4924
- //#region ../../core/mcp/import/clientConfig.ts
4934
+ // ../../core/mcp/import/clientConfig.ts
4925
4935
  function parseJsonObject(raw) {
4926
4936
  let data;
4927
4937
  try {
@@ -4951,8 +4961,7 @@ function parseVsCodeConfig(raw) {
4951
4961
  if (!servers || typeof servers !== "object" || Array.isArray(servers)) throw new Error("No 'servers' object found in VS Code config file");
4952
4962
  return { mcpServers: normalizeServerMap(servers) };
4953
4963
  }
4954
- //#endregion
4955
- //#region ../../core/mcp/import/strategies.ts
4964
+ // ../../core/mcp/import/strategies.ts
4956
4965
  function join$1(...segments) {
4957
4966
  return segments.map((s, i) => i === 0 ? s.replace(/\/+$/, "") : s.replace(/^\/+|\/+$/g, "")).filter((s) => s.length > 0).join("/");
4958
4967
  }
@@ -4993,8 +5002,7 @@ const IMPORT_STRATEGIES = Object.fromEntries([
4993
5002
  function getImportStrategy(id) {
4994
5003
  return IMPORT_STRATEGIES[id];
4995
5004
  }
4996
- //#endregion
4997
- //#region ../../core/mcp/import/resolveSource.ts
5005
+ // ../../core/mcp/import/resolveSource.ts
4998
5006
  function resolveImportSource(type, platform, homeDir, readFile) {
4999
5007
  const strategy = getImportStrategy(type);
5000
5008
  if (!strategy) return null;
@@ -5037,8 +5045,7 @@ function resolveImportSource(type, platform, homeDir, readFile) {
5037
5045
  searched
5038
5046
  };
5039
5047
  }
5040
- //#endregion
5041
- //#region ../../core/mcp/remote/progressToken.ts
5048
+ // ../../core/mcp/remote/progressToken.ts
5042
5049
  function progressTokenOf(message) {
5043
5050
  if ("method" in message && message.method === "notifications/progress" && "params" in message && typeof message.params === "object" && message.params !== null) {
5044
5051
  const parsed = ProgressTokenSchema.safeParse(message.params.progressToken);
@@ -5051,13 +5058,17 @@ function waitForProgressToken(waits, token) {
5051
5058
  const numeric = Number(token);
5052
5059
  return Number.isSafeInteger(numeric) ? waits.get(numeric) : void 0;
5053
5060
  }
5054
- //#endregion
5055
- //#region ../../core/mcp/remote/node/remote-session.ts
5061
+ // ../../core/mcp/remote/node/remote-session.ts
5056
5062
  var RemoteSession = class RemoteSession {
5057
5063
  static DEFAULT_DETACH_GRACE_MS = 6e4;
5058
5064
  static MAX_QUEUED_EVENTS = 1e3;
5059
5065
  sessionId;
5066
+ serverName;
5067
+ transportType;
5068
+ createdAt;
5069
+ lastConsumerSeenAt = null;
5060
5070
  transport;
5071
+ terminated = new AbortController();
5061
5072
  eventQueue = [];
5062
5073
  droppedEventCount = 0;
5063
5074
  detachTimer;
@@ -5072,8 +5083,31 @@ var RemoteSession = class RemoteSession {
5072
5083
  appliedProtocolVersion;
5073
5084
  rateLimits = new RateLimitLedger();
5074
5085
  static PROTOCOL_VERSION_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
5075
- constructor(sessionId) {
5086
+ constructor(sessionId, descriptor = {}) {
5076
5087
  this.sessionId = sessionId;
5088
+ this.serverName = descriptor.serverName;
5089
+ this.transportType = descriptor.transport ?? "stdio";
5090
+ this.createdAt = /* @__PURE__ */ new Date();
5091
+ }
5092
+ get terminatedSignal() {
5093
+ return this.terminated.signal;
5094
+ }
5095
+ terminate() {
5096
+ this.terminated.abort();
5097
+ }
5098
+ describe() {
5099
+ const attached = this.eventConsumer !== null;
5100
+ const lastSeen = attached ? /* @__PURE__ */ new Date() : this.lastConsumerSeenAt;
5101
+ return {
5102
+ sessionId: this.sessionId,
5103
+ ...this.serverName !== void 0 && { serverName: this.serverName },
5104
+ transport: this.transportType,
5105
+ createdAt: this.createdAt.toISOString(),
5106
+ consumerAttached: attached,
5107
+ lastConsumerSeenAt: lastSeen ? lastSeen.toISOString() : null,
5108
+ queuedEvents: this.eventQueue.length,
5109
+ transportDead: this.transportDead
5110
+ };
5077
5111
  }
5078
5112
  setAuthProviderHandle(handle) {
5079
5113
  this.authProviderHandle = handle;
@@ -5093,6 +5127,7 @@ var RemoteSession = class RemoteSession {
5093
5127
  setEventConsumer(consumer) {
5094
5128
  this.cancelDetachGrace();
5095
5129
  this.eventConsumer = consumer;
5130
+ this.lastConsumerSeenAt = /* @__PURE__ */ new Date();
5096
5131
  if (this.droppedEventCount > 0) {
5097
5132
  const dropped = this.droppedEventCount;
5098
5133
  this.droppedEventCount = 0;
@@ -5107,12 +5142,14 @@ var RemoteSession = class RemoteSession {
5107
5142
  while (this.eventQueue.length > 0) consumer(this.eventQueue.shift());
5108
5143
  }
5109
5144
  clearEventConsumer() {
5145
+ if (this.eventConsumer !== null) this.lastConsumerSeenAt = /* @__PURE__ */ new Date();
5110
5146
  this.eventConsumer = null;
5111
5147
  return this.transportDead;
5112
5148
  }
5113
5149
  detachEventConsumer(consumer) {
5114
5150
  if (this.eventConsumer !== consumer) return false;
5115
5151
  this.eventConsumer = null;
5152
+ this.lastConsumerSeenAt = /* @__PURE__ */ new Date();
5116
5153
  return true;
5117
5154
  }
5118
5155
  armDetachGrace(graceMs, onExpire) {
@@ -5301,8 +5338,7 @@ var RemoteSession = class RemoteSession {
5301
5338
  });
5302
5339
  }
5303
5340
  };
5304
- //#endregion
5305
- //#region ../../core/mcp/remote/node/tokenAuthProvider.ts
5341
+ // ../../core/mcp/remote/node/tokenAuthProvider.ts
5306
5342
  const REMOTE_OAUTH_STUB_METADATA = {
5307
5343
  redirect_uris: [],
5308
5344
  scope: ""
@@ -5367,8 +5403,7 @@ function createRemoteAuthProvider(initialAuthState) {
5367
5403
  }
5368
5404
  };
5369
5405
  }
5370
- //#endregion
5371
- //#region ../../core/client/config-parse.ts
5406
+ // ../../core/client/config-parse.ts
5372
5407
  function isAbsoluteHttpUrl(value) {
5373
5408
  let url;
5374
5409
  try {
@@ -5460,8 +5495,7 @@ function formatClientConfigLoadError(error) {
5460
5495
  if (error instanceof Error) return error.message;
5461
5496
  return String(error);
5462
5497
  }
5463
- //#endregion
5464
- //#region ../../core/client/secrets.ts
5498
+ // ../../core/client/secrets.ts
5465
5499
  const CLIENT_KEYCHAIN_ID = "client";
5466
5500
  function hasClientPlaintextSecret(config) {
5467
5501
  const secret = config.enterpriseManagedAuth?.idp?.clientSecret;
@@ -5502,8 +5536,7 @@ function mergeSecretsIntoClientConfig(config, secrets) {
5502
5536
  }
5503
5537
  };
5504
5538
  }
5505
- //#endregion
5506
- //#region ../../core/client/node-persistence.ts
5539
+ // ../../core/client/node-persistence.ts
5507
5540
  async function withClientConfigLock(filePath, action, body) {
5508
5541
  let entered = false;
5509
5542
  try {
@@ -5595,25 +5628,44 @@ async function deleteClientConfigStore(filePath, secretStore) {
5595
5628
  }
5596
5629
  });
5597
5630
  }
5598
- //#endregion
5599
- //#region ../../core/mcp/remote/node/server.ts
5631
+ // ../../core/mcp/remote/node/server.ts
5600
5632
  const SSE_PRIMING_COMMENT = ":\n\n";
5601
5633
  function closeAbortedStream(stream) {
5602
5634
  stream.close().catch(() => {});
5603
5635
  }
5604
- async function primeAndHoldSseStream(stream, cleanup) {
5636
+ async function primeAndHoldSseStream(stream, cleanup, end) {
5605
5637
  let done = false;
5606
- const aborted = new Promise((resolve) => {
5607
- stream.onAbort(() => {
5608
- if (done) return;
5609
- done = true;
5610
- cleanup();
5638
+ const finish = () => {
5639
+ if (done) return false;
5640
+ done = true;
5641
+ cleanup();
5642
+ return true;
5643
+ };
5644
+ const released = new Promise((resolve) => {
5645
+ let closed = false;
5646
+ const release = () => {
5647
+ if (closed) return;
5648
+ closed = true;
5611
5649
  closeAbortedStream(stream);
5612
5650
  resolve();
5651
+ };
5652
+ let detachEnd = () => {};
5653
+ stream.onAbort(() => {
5654
+ if (finish()) detachEnd();
5655
+ release();
5613
5656
  });
5657
+ if (!end) return;
5658
+ const { signal, flush } = end;
5659
+ const onEnd = () => {
5660
+ if (!finish()) return;
5661
+ flush().catch(() => {}).then(release);
5662
+ };
5663
+ detachEnd = () => signal.removeEventListener("abort", onEnd);
5664
+ if (signal.aborted) onEnd();
5665
+ else signal.addEventListener("abort", onEnd, { once: true });
5614
5666
  });
5615
5667
  await stream.write(SSE_PRIMING_COMMENT);
5616
- await aborted;
5668
+ await released;
5617
5669
  }
5618
5670
  const MAX_APP_DOCUMENT_CHARS = 8388608;
5619
5671
  const MAX_APP_DOCUMENT_BODY_BYTES = 25165824;
@@ -5720,6 +5772,13 @@ function mcpParamHeadersOnly(headers) {
5720
5772
  for (const [key, value] of Object.entries(headers)) if (typeof value === "string" && key.toLowerCase().startsWith("Mcp-Param-".toLowerCase())) out[key] = value;
5721
5773
  return Object.keys(out).length > 0 ? out : void 0;
5722
5774
  }
5775
+ const SESSION_TERMINATED_MESSAGE = "Session terminated from the Inspector's active session list";
5776
+ const MAX_SESSION_SERVER_NAME_CHARS = 256;
5777
+ function sessionServerName(value) {
5778
+ if (typeof value !== "string") return void 0;
5779
+ const name = value.trim();
5780
+ return name === "" ? void 0 : name.slice(0, MAX_SESSION_SERVER_NAME_CHARS);
5781
+ }
5723
5782
  function createRemoteApp(options) {
5724
5783
  const dangerouslyOmitAuth = !!options.dangerouslyOmitAuth;
5725
5784
  const authToken = dangerouslyOmitAuth ? "" : options.authToken || process.env[API_SERVER_ENV_VARS.AUTH_TOKEN] || randomBytes(32).toString("hex");
@@ -5730,7 +5789,8 @@ function createRemoteApp(options) {
5730
5789
  session.armDetachGrace(sessionDetachGraceMs, () => {
5731
5790
  sessions.delete(session.sessionId);
5732
5791
  session.rejectActiveRequestWaits(/* @__PURE__ */ new Error("Session closed: no client attached"));
5733
- session.transport.close().catch(() => {});
5792
+ const transport = session.transport;
5793
+ terminateSessionBestEffort(transport).then(() => transport.close().catch(() => {}));
5734
5794
  });
5735
5795
  };
5736
5796
  const { logger: fileLogger, allowedOrigins } = options;
@@ -5846,7 +5906,10 @@ function createRemoteApp(options) {
5846
5906
  const config = body.config;
5847
5907
  if (!config) return c.json({ error: "Missing config" }, 400);
5848
5908
  const sessionId = crypto.randomUUID();
5849
- const session = new RemoteSession(sessionId);
5909
+ const session = new RemoteSession(sessionId, {
5910
+ serverName: sessionServerName(body.serverName),
5911
+ transport: config.type ?? "stdio"
5912
+ });
5850
5913
  let transport;
5851
5914
  let authHandle;
5852
5915
  try {
@@ -6010,12 +6073,13 @@ function createRemoteApp(options) {
6010
6073
  const session = sessions.get(sessionId);
6011
6074
  if (!session) return c.json({ error: "Session not found" }, 404);
6012
6075
  return streamSSE(c, async (stream) => {
6076
+ let lastWrite = Promise.resolve();
6013
6077
  const consumer = (event) => {
6014
6078
  const data = JSON.stringify(event);
6015
- stream.writeSSE({
6079
+ lastWrite = stream.writeSSE({
6016
6080
  event: event.type,
6017
6081
  data
6018
- });
6082
+ }).catch(() => {});
6019
6083
  };
6020
6084
  session.setEventConsumer(consumer);
6021
6085
  if (session.isTransportDead()) {
@@ -6031,6 +6095,9 @@ function createRemoteApp(options) {
6031
6095
  return;
6032
6096
  }
6033
6097
  armSessionReap(session);
6098
+ }, {
6099
+ signal: session.terminatedSignal,
6100
+ flush: () => lastWrite
6034
6101
  });
6035
6102
  });
6036
6103
  });
@@ -6047,11 +6114,28 @@ function createRemoteApp(options) {
6047
6114
  if (session) {
6048
6115
  session.cancelDetachGrace();
6049
6116
  session.clearEventConsumer();
6117
+ await terminateSessionBestEffort(session.transport);
6050
6118
  await session.transport.close();
6051
6119
  sessions.delete(sessionId);
6052
6120
  }
6053
6121
  return c.json({ ok: true });
6054
6122
  });
6123
+ app.get("/api/mcp/sessions", (c) => {
6124
+ const list = { sessions: [...sessions.values()].map((session) => session.describe()).sort((a, b) => a.createdAt.localeCompare(b.createdAt)) };
6125
+ return c.json(list);
6126
+ });
6127
+ app.delete("/api/mcp/sessions/:sessionId", async (c) => {
6128
+ const sessionId = c.req.param("sessionId");
6129
+ const session = sessions.get(sessionId);
6130
+ if (!session) return c.json({ error: "Session not found" }, 404);
6131
+ sessions.delete(sessionId);
6132
+ session.cancelDetachGrace();
6133
+ session.markTransportDead(SESSION_TERMINATED_MESSAGE);
6134
+ session.terminate();
6135
+ session.rejectActiveRequestWaits(/* @__PURE__ */ new Error(SESSION_TERMINATED_MESSAGE));
6136
+ await session.transport.close().catch(() => {});
6137
+ return c.json({ ok: true });
6138
+ });
6055
6139
  app.post("/api/mcp/auth-state", async (c) => {
6056
6140
  let body;
6057
6141
  try {
@@ -6143,7 +6227,14 @@ function createRemoteApp(options) {
6143
6227
  timeoutMs: deadlineMs
6144
6228
  }, 504);
6145
6229
  const refused = findFetchTargetError(err);
6146
- if (refused) return c.json({ error: refused.message }, 403);
6230
+ if (refused) {
6231
+ const body = {
6232
+ error: refused.message,
6233
+ code: FETCH_TARGET_REFUSED_WIRE_CODE,
6234
+ url: redactUrlQuery(refused.url ?? url)
6235
+ };
6236
+ return c.json(body, 403);
6237
+ }
6147
6238
  return c.json({ error: msg }, 500);
6148
6239
  } finally {
6149
6240
  if (timer !== void 0) clearTimeout(timer);
@@ -6989,8 +7080,7 @@ function createRemoteApp(options) {
6989
7080
  }
6990
7081
  };
6991
7082
  }
6992
- //#endregion
6993
- //#region server/inject-auth-token.ts
7083
+ // server/inject-auth-token.ts
6994
7084
  function serializeTokenForScript(token) {
6995
7085
  return JSON.stringify(token).replace(/</g, "\\u003c");
6996
7086
  }
@@ -7003,8 +7093,7 @@ function injectAuthToken(html, token) {
7003
7093
  if (bodyClose !== -1) return html.slice(0, bodyClose) + script + html.slice(bodyClose);
7004
7094
  return script + html;
7005
7095
  }
7006
- //#endregion
7007
- //#region server/health.ts
7096
+ // server/health.ts
7008
7097
  const HEALTH_PATH = "/healthz";
7009
7098
  const HEALTH_BODY = Object.freeze({ status: "ok" });
7010
7099
  const HEALTH_HEADERS = Object.freeze({
@@ -7034,8 +7123,7 @@ function handleNodeHealthRequest(req, res) {
7034
7123
  else res.end(body);
7035
7124
  return true;
7036
7125
  }
7037
- //#endregion
7038
- //#region server/node-request-bridge.ts
7126
+ // server/node-request-bridge.ts
7039
7127
  function fetchUrlForNodeRequest(headers, pathname, scheme) {
7040
7128
  return `${scheme}://${headers.host ?? headers[":authority"]}${pathname}`;
7041
7129
  }
@@ -7057,8 +7145,7 @@ const CONNECTION_SPECIFIC_HEADERS = /* @__PURE__ */ new Set([
7057
7145
  function isResponseHeaderAllowed(name, httpVersionMajor) {
7058
7146
  return httpVersionMajor < 2 || !CONNECTION_SPECIFIC_HEADERS.has(name.toLowerCase());
7059
7147
  }
7060
- //#endregion
7061
- //#region server/vite-hono-plugin.ts
7148
+ // server/vite-hono-plugin.ts
7062
7149
  function honoMiddlewarePlugin(config) {
7063
7150
  let resolvedAuthToken = "";
7064
7151
  return {
@@ -7200,8 +7287,7 @@ function honoMiddlewarePlugin(config) {
7200
7287
  }
7201
7288
  };
7202
7289
  }
7203
- //#endregion
7204
- //#region server/vite-base-config.ts
7290
+ // server/vite-base-config.ts
7205
7291
  const NODE_ONLY_OPTIMIZE_DEPS_EXCLUDE = [
7206
7292
  "@modelcontextprotocol/client/stdio",
7207
7293
  "atomically",
@@ -7344,8 +7430,7 @@ function vitestSharedPaths(clientDir) {
7344
7430
  }
7345
7431
  };
7346
7432
  }
7347
- //#endregion
7348
- //#region server/start-vite-dev-server.ts
7433
+ // server/start-vite-dev-server.ts
7349
7434
  const __dirname$2 = dirname(fileURLToPath(import.meta.url));
7350
7435
  async function startViteDevServer(config) {
7351
7436
  const root = resolve(join(__dirname$2, ".."));
@@ -7378,8 +7463,7 @@ async function startViteDevServer(config) {
7378
7463
  await server.close();
7379
7464
  } };
7380
7465
  }
7381
- //#endregion
7382
- //#region server/server.ts
7466
+ // server/server.ts
7383
7467
  function isApiPath(path) {
7384
7468
  return path === "/api" || path.startsWith("/api/");
7385
7469
  }
@@ -7481,8 +7565,7 @@ async function startHonoServer(config) {
7481
7565
  });
7482
7566
  } };
7483
7567
  }
7484
- //#endregion
7485
- //#region server/ensure-web-build.ts
7568
+ // server/ensure-web-build.ts
7486
7569
  function runViteBuild(webRoot, log) {
7487
7570
  const result = spawnSync("npm", ["run", "build:client"], {
7488
7571
  cwd: webRoot,
@@ -7501,8 +7584,7 @@ function ensureWebBuild(webRoot, distRoot, deps = {}) {
7501
7584
  log("No production web build found at clients/web/dist. Building the web UI now (first run only; this can take a minute)...");
7502
7585
  if (build(webRoot, log) !== 0 || !exists(indexHtml)) throw new Error("Could not build the web UI automatically. Build it manually with `npm run build` (run from clients/web), or launch with `--dev` to use the Vite dev server.");
7503
7586
  }
7504
- //#endregion
7505
- //#region server/run-web.ts
7587
+ // server/run-web.ts
7506
7588
  const __dirname = dirname(fileURLToPath(import.meta.url));
7507
7589
  function ensureStdioCwd(config) {
7508
7590
  if ((config.type === "stdio" || config.type === void 0) && config.command && !config.cwd) return {
@@ -7631,12 +7713,10 @@ async function runWeb(argv) {
7631
7713
  process.on("SIGTERM", shutdown);
7632
7714
  return new Promise(() => {});
7633
7715
  }
7634
- //#endregion
7635
- //#region src/index.ts
7716
+ // src/index.ts
7636
7717
  const __filename = fileURLToPath(import.meta.url);
7637
7718
  if (process.argv[1] !== void 0 && resolve(process.argv[1]) === resolve(__filename)) runWeb(process.argv).then((code) => process.exit(code ?? 0)).catch((e) => {
7638
7719
  console.error(e);
7639
7720
  process.exit(1);
7640
7721
  });
7641
- //#endregion
7642
7722
  export { runWeb };