@modelcontextprotocol/inspector 2.9.0 → 2.10.1

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.
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { resolve as resolve8 } from "path";
4
+ import { resolve as resolve9 } from "path";
5
5
  import { fileURLToPath as fileURLToPath7 } from "url";
6
6
 
7
7
  // server/run-web.ts
8
- import { resolve as resolve7, join as join10, dirname as dirname9 } from "path";
8
+ import { resolve as resolve8, join as join10, dirname as dirname9 } from "path";
9
9
  import { fileURLToPath as fileURLToPath6 } from "url";
10
10
  import { Command } from "commander";
11
11
 
@@ -94,6 +94,7 @@ var DEFAULT_TASK_TTL_MS = 6e4;
94
94
  var DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
95
95
  var DEFAULT_MAX_FETCH_REQUESTS = 1e3;
96
96
  var DEFAULT_PROTOCOL_ERA = "legacy";
97
+ var DEFAULT_ELICIT_CAPABILITY = "both";
97
98
  var DEFAULT_MODERN_LOG_LEVEL = "debug";
98
99
  var MODERN_LOG_LEVELS = [
99
100
  "off",
@@ -285,6 +286,15 @@ var VALID_PROTOCOL_ERAS = /* @__PURE__ */ new Set([
285
286
  "auto",
286
287
  "modern"
287
288
  ]);
289
+ var VALID_ELICIT_CAPABILITIES = /* @__PURE__ */ new Set([
290
+ "off",
291
+ "url",
292
+ "form",
293
+ "both"
294
+ ]);
295
+ function isElicitCapability(value) {
296
+ return typeof value === "string" && VALID_ELICIT_CAPABILITIES.has(value);
297
+ }
288
298
  function isProtocolEra(value) {
289
299
  return typeof value === "string" && VALID_PROTOCOL_ERAS.has(value);
290
300
  }
@@ -429,7 +439,7 @@ function cleanEndpointOverride(value, field) {
429
439
  return value.trim() || void 0;
430
440
  }
431
441
  function storedFieldsToInspectorSettings(stored) {
432
- const hasAny = stored.headers !== void 0 || stored.metadata !== void 0 || stored.connectionTimeout !== void 0 || stored.requestTimeout !== void 0 || stored.taskTtl !== void 0 || stored.autoRefreshOnListChanged !== void 0 || stored.paginatedLists !== void 0 || stored.suppressNotificationStream !== void 0 || stored.advertisedExtensions !== void 0 || stored.maxFetchRequests !== void 0 || stored.skillCatalogMaxSkills !== void 0 || stored.skillCatalogMaxBytes !== void 0 || stored.oauth !== void 0 || stored.roots !== void 0 || stored.protocolEra !== void 0 || stored.modernLogLevel !== void 0 || stored.env !== void 0 || stored.cwd !== void 0;
442
+ const hasAny = stored.headers !== void 0 || stored.metadata !== void 0 || stored.connectionTimeout !== void 0 || stored.requestTimeout !== void 0 || stored.taskTtl !== void 0 || stored.autoRefreshOnListChanged !== void 0 || stored.paginatedLists !== void 0 || stored.suppressNotificationStream !== void 0 || stored.advertisedExtensions !== void 0 || stored.maxFetchRequests !== void 0 || stored.skillCatalogMaxSkills !== void 0 || stored.skillCatalogMaxBytes !== void 0 || stored.oauth !== void 0 || stored.roots !== void 0 || stored.protocolEra !== void 0 || stored.elicitCapability !== void 0 || stored.modernLogLevel !== void 0 || stored.env !== void 0 || stored.cwd !== void 0;
433
443
  if (!hasAny) return void 0;
434
444
  const headersPairs = stored.headers ? Object.entries(stored.headers).map(([key, value]) => ({ key, value })) : [];
435
445
  const settings = {
@@ -467,6 +477,9 @@ function storedFieldsToInspectorSettings(stored) {
467
477
  if (isProtocolEra(stored.protocolEra)) {
468
478
  settings.protocolEra = stored.protocolEra;
469
479
  }
480
+ if (isElicitCapability(stored.elicitCapability)) {
481
+ settings.elicitCapability = stored.elicitCapability;
482
+ }
470
483
  if (isModernLogLevel(stored.modernLogLevel)) {
471
484
  settings.modernLogLevel = stored.modernLogLevel;
472
485
  }
@@ -542,6 +555,9 @@ function inspectorSettingsToStoredFields(settings) {
542
555
  if (settings.protocolEra !== void 0 && settings.protocolEra !== DEFAULT_PROTOCOL_ERA) {
543
556
  out.protocolEra = settings.protocolEra;
544
557
  }
558
+ if (settings.elicitCapability !== void 0 && settings.elicitCapability !== DEFAULT_ELICIT_CAPABILITY) {
559
+ out.elicitCapability = settings.elicitCapability;
560
+ }
545
561
  if (settings.modernLogLevel !== void 0 && settings.modernLogLevel !== DEFAULT_MODERN_LOG_LEVEL) {
546
562
  out.modernLogLevel = settings.modernLogLevel;
547
563
  }
@@ -596,6 +612,7 @@ var INSPECTOR_FIELD_KEY_MAP = {
596
612
  headers: true,
597
613
  metadata: true,
598
614
  protocolEra: true,
615
+ elicitCapability: true,
599
616
  modernLogLevel: true,
600
617
  connectionTimeout: true,
601
618
  requestTimeout: true,
@@ -700,6 +717,19 @@ var DEFAULT_SEED_CONFIG = {
700
717
  }
701
718
  };
702
719
 
720
+ // ../../core/storage/own-entry.ts
721
+ function setOwnEntry(map, key, value) {
722
+ Object.defineProperty(map, key, {
723
+ value,
724
+ enumerable: true,
725
+ writable: true,
726
+ configurable: true
727
+ });
728
+ }
729
+ function getOwnEntry(map, key) {
730
+ return map !== void 0 && Object.hasOwn(map, key) ? map[key] : void 0;
731
+ }
732
+
703
733
  // ../../core/mcp/node/config.ts
704
734
  function parseKeyValuePair(value, previous = {}) {
705
735
  const parts = value.split("=");
@@ -778,13 +808,14 @@ function loadMcpServersConfig(configPath, writable) {
778
808
  }
779
809
  function loadServerFromConfig(configPath, serverName, writable) {
780
810
  const config = loadMcpServersConfig(configPath, writable);
781
- if (!config.mcpServers[serverName]) {
811
+ const server = getOwnEntry(config.mcpServers, serverName);
812
+ if (!server) {
782
813
  const available = Object.keys(config.mcpServers).join(", ");
783
814
  throw new Error(
784
815
  `Server '${serverName}' not found in config file. Available servers: ${available}`
785
816
  );
786
817
  }
787
- return config.mcpServers[serverName];
818
+ return server;
788
819
  }
789
820
  function buildConfigFromOptions(options) {
790
821
  const target = options.target ?? [];
@@ -922,7 +953,6 @@ function resolveServerConfigs(options, mode) {
922
953
  }
923
954
 
924
955
  // server/web-server-config.ts
925
- import open from "open";
926
956
  import pino from "pino";
927
957
 
928
958
  // ../../core/mcp/remote/constants.ts
@@ -1014,6 +1044,32 @@ function readInspectorVersionSafe(callerUrl) {
1014
1044
  }
1015
1045
  }
1016
1046
 
1047
+ // ../../core/node/openUrl.ts
1048
+ import open from "open";
1049
+ var OPEN_URL_TIMEOUT_MS = 5e3;
1050
+ function launched(child) {
1051
+ return new Promise((resolve10, reject) => {
1052
+ child.on("error", reject);
1053
+ child.once("spawn", () => resolve10());
1054
+ });
1055
+ }
1056
+ async function openUrl(url, timeoutMs = OPEN_URL_TIMEOUT_MS) {
1057
+ const href = typeof url === "string" ? url : url.href;
1058
+ let timer;
1059
+ const timeout = new Promise((_, reject) => {
1060
+ timer = setTimeout(
1061
+ () => reject(new Error(`browser did not open within ${timeoutMs / 1e3}s`)),
1062
+ timeoutMs
1063
+ );
1064
+ });
1065
+ try {
1066
+ const opened = Promise.resolve().then(() => open(href)).then(launched);
1067
+ await Promise.race([opened, timeout]);
1068
+ } finally {
1069
+ clearTimeout(timer);
1070
+ }
1071
+ }
1072
+
1017
1073
  // server/sandbox-controller.ts
1018
1074
  import { createServer } from "http";
1019
1075
  import { readFileSync as readFileSync3 } from "fs";
@@ -1151,12 +1207,12 @@ function createSandboxController(options) {
1151
1207
  if (server && sandboxUrl) {
1152
1208
  return { port: boundPort, url: sandboxUrl };
1153
1209
  }
1154
- return new Promise((resolve9) => {
1210
+ return new Promise((resolve10) => {
1155
1211
  let settled = false;
1156
1212
  const settle = (value) => {
1157
1213
  if (settled) return;
1158
1214
  settled = true;
1159
- resolve9(value);
1215
+ resolve10(value);
1160
1216
  };
1161
1217
  server = createServer((req, res) => {
1162
1218
  if (req.method !== "GET" || req.url !== "/sandbox" && req.url !== "/sandbox/") {
@@ -1218,11 +1274,11 @@ function createSandboxController(options) {
1218
1274
  },
1219
1275
  async close() {
1220
1276
  if (!server) return;
1221
- return new Promise((resolve9) => {
1277
+ return new Promise((resolve10) => {
1222
1278
  server.close(() => {
1223
1279
  server = null;
1224
1280
  sandboxUrl = null;
1225
- resolve9();
1281
+ resolve10();
1226
1282
  });
1227
1283
  });
1228
1284
  },
@@ -1300,12 +1356,12 @@ function createAppOriginController(options) {
1300
1356
  if (server && origin) {
1301
1357
  return { port: boundPort, url: origin };
1302
1358
  }
1303
- return new Promise((resolve9) => {
1359
+ return new Promise((resolve10) => {
1304
1360
  let settled = false;
1305
1361
  const settle = (value) => {
1306
1362
  if (settled) return;
1307
1363
  settled = true;
1308
- resolve9(value);
1364
+ resolve10(value);
1309
1365
  };
1310
1366
  server = createServer2((req, res) => {
1311
1367
  const id = req.method === "GET" ? parseDocumentId(req.url) : null;
@@ -1389,11 +1445,11 @@ function createAppOriginController(options) {
1389
1445
  documents.clear();
1390
1446
  retainedChars = 0;
1391
1447
  if (!server) return;
1392
- return new Promise((resolve9) => {
1448
+ return new Promise((resolve10) => {
1393
1449
  server.close(() => {
1394
1450
  server = null;
1395
1451
  origin = null;
1396
- resolve9();
1452
+ resolve10();
1397
1453
  });
1398
1454
  });
1399
1455
  },
@@ -1626,7 +1682,7 @@ MCP Inspector Web is up and running at:
1626
1682
  return url;
1627
1683
  }
1628
1684
  function openBrowser(url) {
1629
- open(url).catch((err) => {
1685
+ openUrl(url).catch((err) => {
1630
1686
  console.warn("Could not open a browser automatically:", err);
1631
1687
  });
1632
1688
  }
@@ -1743,7 +1799,7 @@ function resolveAutoOpen() {
1743
1799
  }
1744
1800
 
1745
1801
  // server/start-vite-dev-server.ts
1746
- import { join as join7, dirname as dirname7, resolve as resolve6 } from "path";
1802
+ import { join as join7, dirname as dirname7, resolve as resolve7 } from "path";
1747
1803
  import { fileURLToPath as fileURLToPath4 } from "url";
1748
1804
  import { createServer as createServer3 } from "vite";
1749
1805
  import react from "@vitejs/plugin-react";
@@ -1937,8 +1993,8 @@ async function readChallengeBody(response) {
1937
1993
  let text = "";
1938
1994
  let bytes = 0;
1939
1995
  let timer;
1940
- const deadline = new Promise((resolve9) => {
1941
- timer = setTimeout(() => resolve9("timeout"), CHALLENGE_BODY_READ_MS);
1996
+ const deadline = new Promise((resolve10) => {
1997
+ timer = setTimeout(() => resolve10("timeout"), CHALLENGE_BODY_READ_MS);
1942
1998
  });
1943
1999
  try {
1944
2000
  while (bytes < CHALLENGE_BODY_MAX_BYTES) {
@@ -2567,19 +2623,6 @@ function createTransportNode(config, options = {}) {
2567
2623
  // ../../core/auth/requestTimeout.ts
2568
2624
  var OAUTH_TIMEOUT_WIRE_CODE = "oauth_request_timeout";
2569
2625
 
2570
- // ../../core/storage/own-entry.ts
2571
- function setOwnEntry(map, key, value) {
2572
- Object.defineProperty(map, key, {
2573
- value,
2574
- enumerable: true,
2575
- writable: true,
2576
- configurable: true
2577
- });
2578
- }
2579
- function getOwnEntry(map, key) {
2580
- return map !== void 0 && Object.hasOwn(map, key) ? map[key] : void 0;
2581
- }
2582
-
2583
2626
  // ../../core/auth/oauth-persist.ts
2584
2627
  import { OAuthTokensSchema } from "@modelcontextprotocol/core";
2585
2628
  var OAUTH_PERSIST_STORE_ID = "oauth";
@@ -3191,9 +3234,9 @@ async function openSecretFileLock(filePath) {
3191
3234
  }
3192
3235
  async function withSecretFileLock(filePath, fn) {
3193
3236
  const release = await openSecretFileLock(filePath);
3194
- if (release === null) return fn();
3237
+ if (release === null) return fn(false);
3195
3238
  try {
3196
- return await fn();
3239
+ return await fn(true);
3197
3240
  } finally {
3198
3241
  await release();
3199
3242
  }
@@ -3210,10 +3253,10 @@ import * as crypto2 from "crypto";
3210
3253
  import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
3211
3254
  import * as fs3 from "fs/promises";
3212
3255
  import * as path3 from "path";
3213
- var scrypt2 = (passphrase, salt, keylen, options) => new Promise((resolve9, reject) => {
3256
+ var scrypt2 = (passphrase, salt, keylen, options) => new Promise((resolve10, reject) => {
3214
3257
  crypto2.scrypt(passphrase, salt, keylen, options, (err, key) => {
3215
3258
  if (err) reject(err);
3216
- else resolve9(key);
3259
+ else resolve10(key);
3217
3260
  });
3218
3261
  });
3219
3262
  var FORMAT_VERSION = 1;
@@ -4031,9 +4074,13 @@ async function describeFileStore(store, filePath, kind, reason, detail) {
4031
4074
  };
4032
4075
  }
4033
4076
  function chooseFallbackKind(opts) {
4077
+ if (opts.allowMemory === false) return "file";
4034
4078
  return opts.container && !opts.mounted ? "memory" : "file";
4035
4079
  }
4036
- function warnAboutSecretStorage(info) {
4080
+ var memoryFallbackAllowed = true;
4081
+ var secretStorageWarningsQuiet = false;
4082
+ function warnAboutSecretStorage(info, opts) {
4083
+ if (secretStorageWarningsQuiet && opts?.force !== true) return;
4037
4084
  if (info.reason === "fallback") {
4038
4085
  console.warn(
4039
4086
  `
@@ -4070,7 +4117,8 @@ function resolveSecretStore() {
4070
4117
  }
4071
4118
  const kind = chooseFallbackKind({
4072
4119
  container: isContainer(),
4073
- mounted: isOnMountPoint(path4.dirname(defaultSecretFilePath()))
4120
+ mounted: isOnMountPoint(path4.dirname(defaultSecretFilePath())),
4121
+ allowMemory: memoryFallbackAllowed
4074
4122
  });
4075
4123
  const result = await buildStore(kind, "fallback", probe.detail);
4076
4124
  warnAboutSecretStorage(result.info);
@@ -4277,8 +4325,15 @@ var DeferredSecretStore = class {
4277
4325
  function defaultSecretStore() {
4278
4326
  return new DeferredSecretStore();
4279
4327
  }
4328
+ async function resolveConcreteSecretStore(store) {
4329
+ return store instanceof DeferredSecretStore ? (await resolveSecretStore()).store : store;
4330
+ }
4331
+
4332
+ // ../../core/auth/node/oauth-namespace-ledger.ts
4333
+ import { resolve as resolve6 } from "path";
4280
4334
 
4281
4335
  // ../../core/auth/node/oauth-secrets.ts
4336
+ import { randomUUID as randomUUID2 } from "crypto";
4282
4337
  import { OAuthTokensSchema as OAuthTokensSchema2 } from "@modelcontextprotocol/core";
4283
4338
  var PERSIST_TOKENS_ENV = "MCP_INSPECTOR_PERSIST_TOKENS";
4284
4339
  var warnedPolicyValues = /* @__PURE__ */ new Set();
@@ -4294,8 +4349,14 @@ function getPersistTokensPolicy(env = process.env) {
4294
4349
  }
4295
4350
  return "all";
4296
4351
  }
4297
- var oauthSecretServerId = (serverUrl) => `oauth+${encodeURIComponent(serverUrl)}`;
4298
- var oauthIdpSecretServerId = (issuer) => `oauth-idp+${encodeURIComponent(issuer)}`;
4352
+ var oauthSecretServerId = (serverUrl, namespace) => namespace === void 0 ? `oauth+${encodeURIComponent(serverUrl)}` : `oauth+${namespace}+${encodeURIComponent(serverUrl)}`;
4353
+ var oauthIdpSecretServerId = (issuer, namespace) => namespace === void 0 ? `oauth-idp+${encodeURIComponent(issuer)}` : `oauth-idp+${namespace}+${encodeURIComponent(issuer)}`;
4354
+ function isValidSecretsNamespace(value) {
4355
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(value);
4356
+ }
4357
+ function newSecretsNamespace() {
4358
+ return randomUUID2();
4359
+ }
4299
4360
  var issuerTokensField = (issuer) => `tokens:${issuer}`;
4300
4361
  var issuerClientSecretField = (issuer) => `client-secret:${issuer}`;
4301
4362
  var issuerRegistrationTokenField = (issuer) => `registration-token:${issuer}`;
@@ -4552,6 +4613,175 @@ function snapshotHasPlaintextSecrets(snapshot) {
4552
4613
  return false;
4553
4614
  }
4554
4615
 
4616
+ // ../../core/auth/node/oauth-namespace-ledger.ts
4617
+ var namespaceLedgerPath = (stateFilePath) => `${stateFilePath}.namespaces.json`;
4618
+ var KEYRING_LOCATION = "keyring";
4619
+ var FILE_LOCATION_PREFIX = "file:";
4620
+ async function secretStoreLocation(store) {
4621
+ const concrete = await resolveConcreteSecretStore(store);
4622
+ if (concrete instanceof KeyringSecretStore) return KEYRING_LOCATION;
4623
+ if (concrete instanceof FileSecretStore) {
4624
+ return `${FILE_LOCATION_PREFIX}${resolve6(concrete.filePath)}`;
4625
+ }
4626
+ return "memory";
4627
+ }
4628
+ function coveredLocations(location, byLocation) {
4629
+ return [...byLocation].filter(
4630
+ ([recorded]) => recorded === location || location === KEYRING_LOCATION && recorded.startsWith(FILE_LOCATION_PREFIX)
4631
+ ).map(([recorded, keys]) => ({ location: recorded, keys }));
4632
+ }
4633
+ var warnedLedgerFailures = /* @__PURE__ */ new Set();
4634
+ function warnLedgerFailure(what, error) {
4635
+ const reason = error instanceof Error ? error.message : String(error);
4636
+ const key = `${what}:${reason}`;
4637
+ if (warnedLedgerFailures.has(key)) return;
4638
+ warnedLedgerFailures.add(key);
4639
+ console.warn(
4640
+ `[mcp-inspector] Could not ${what} the OAuth secrets-namespace ledger (${reason}). OAuth state is unaffected, but secret-store entries left behind if this state file's namespace is ever lost (for example, after a save by an older Inspector) may not be cleaned up automatically.`
4641
+ );
4642
+ }
4643
+ function isRecord3(value) {
4644
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4645
+ }
4646
+ function stringsOf(value) {
4647
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
4648
+ }
4649
+ function parseLedger(raw) {
4650
+ const ledger = /* @__PURE__ */ new Map();
4651
+ if (raw === null) return ledger;
4652
+ let parsed;
4653
+ try {
4654
+ parsed = JSON.parse(raw);
4655
+ } catch {
4656
+ return ledger;
4657
+ }
4658
+ const namespaces = isRecord3(parsed) ? parsed.namespaces : void 0;
4659
+ if (!isRecord3(namespaces)) return ledger;
4660
+ for (const [namespace, locations] of Object.entries(namespaces)) {
4661
+ if (!isValidSecretsNamespace(namespace) || !isRecord3(locations)) continue;
4662
+ const byLocation = /* @__PURE__ */ new Map();
4663
+ for (const [location, keys] of Object.entries(locations)) {
4664
+ if (!isRecord3(keys)) continue;
4665
+ byLocation.set(location, {
4666
+ servers: new Set(stringsOf(keys.servers)),
4667
+ idpSessions: new Set(stringsOf(keys.idpSessions))
4668
+ });
4669
+ }
4670
+ if (byLocation.size > 0) ledger.set(namespace, byLocation);
4671
+ }
4672
+ return ledger;
4673
+ }
4674
+ function serializeLedger(ledger) {
4675
+ const namespaces = Object.fromEntries(
4676
+ [...ledger].map(([namespace, byLocation]) => [
4677
+ namespace,
4678
+ Object.fromEntries(
4679
+ [...byLocation].map(([location, keys]) => [
4680
+ location,
4681
+ { servers: [...keys.servers], idpSessions: [...keys.idpSessions] }
4682
+ ])
4683
+ )
4684
+ ])
4685
+ );
4686
+ return serializeStore({ namespaces });
4687
+ }
4688
+ async function writeLedger(stateFilePath, ledger) {
4689
+ const path6 = namespaceLedgerPath(stateFilePath);
4690
+ if (ledger.size === 0) await deleteStoreFile(path6);
4691
+ else await writeStoreFile(path6, serializeLedger(ledger));
4692
+ }
4693
+ async function recordNamespaceKeys(stateFilePath, secretStore, namespace, servers, idpSessions) {
4694
+ try {
4695
+ const ledger = parseLedger(
4696
+ await readStoreFile(namespaceLedgerPath(stateFilePath))
4697
+ );
4698
+ const location = await secretStoreLocation(secretStore);
4699
+ let byLocation = ledger.get(namespace);
4700
+ if (!byLocation) {
4701
+ byLocation = /* @__PURE__ */ new Map();
4702
+ ledger.set(namespace, byLocation);
4703
+ }
4704
+ let keys = byLocation.get(location);
4705
+ let changed = false;
4706
+ if (!keys) {
4707
+ keys = { servers: /* @__PURE__ */ new Set(), idpSessions: /* @__PURE__ */ new Set() };
4708
+ byLocation.set(location, keys);
4709
+ changed = true;
4710
+ }
4711
+ for (const url of servers) {
4712
+ if (keys.servers.has(url)) continue;
4713
+ keys.servers.add(url);
4714
+ changed = true;
4715
+ }
4716
+ for (const issuer of idpSessions) {
4717
+ if (keys.idpSessions.has(issuer)) continue;
4718
+ keys.idpSessions.add(issuer);
4719
+ changed = true;
4720
+ }
4721
+ if (changed) await writeLedger(stateFilePath, ledger);
4722
+ } catch (error) {
4723
+ warnLedgerFailure("update", error);
4724
+ }
4725
+ }
4726
+ async function purgeSupersededNamespaces(stateFilePath, secretStore, current) {
4727
+ let ledger;
4728
+ let location;
4729
+ try {
4730
+ ledger = parseLedger(
4731
+ await readStoreFile(namespaceLedgerPath(stateFilePath))
4732
+ );
4733
+ location = await secretStoreLocation(secretStore);
4734
+ } catch (error) {
4735
+ warnLedgerFailure("read", error);
4736
+ return;
4737
+ }
4738
+ let changed = false;
4739
+ for (const [namespace, byLocation] of ledger) {
4740
+ if (namespace === current) continue;
4741
+ for (const { location: recorded, keys } of coveredLocations(
4742
+ location,
4743
+ byLocation
4744
+ )) {
4745
+ const purges = [
4746
+ ...[...keys.servers].map(
4747
+ (url) => () => oauthSecretServerId(url, namespace)
4748
+ ),
4749
+ ...[...keys.idpSessions].map(
4750
+ (issuer) => () => oauthIdpSecretServerId(issuer, namespace)
4751
+ )
4752
+ ];
4753
+ let purged = true;
4754
+ for (const idOf of purges) {
4755
+ try {
4756
+ await secretStore.deleteAllForServer(idOf());
4757
+ } catch (error) {
4758
+ purged = false;
4759
+ warnLedgerFailure("purge an orphaned namespace recorded in", error);
4760
+ }
4761
+ }
4762
+ if (!purged || recorded !== location) continue;
4763
+ byLocation.delete(recorded);
4764
+ if (recorded.startsWith(FILE_LOCATION_PREFIX)) {
4765
+ const keyring = byLocation.get(KEYRING_LOCATION) ?? {
4766
+ servers: /* @__PURE__ */ new Set(),
4767
+ idpSessions: /* @__PURE__ */ new Set()
4768
+ };
4769
+ for (const url of keys.servers) keyring.servers.add(url);
4770
+ for (const issuer of keys.idpSessions) keyring.idpSessions.add(issuer);
4771
+ byLocation.set(KEYRING_LOCATION, keyring);
4772
+ }
4773
+ changed = true;
4774
+ }
4775
+ if (byLocation.size === 0) ledger.delete(namespace);
4776
+ }
4777
+ if (!changed) return;
4778
+ try {
4779
+ await writeLedger(stateFilePath, ledger);
4780
+ } catch (error) {
4781
+ warnLedgerFailure("update", error);
4782
+ }
4783
+ }
4784
+
4555
4785
  // ../../core/auth/node/oauth-persist-file.ts
4556
4786
  var warnedStoreFailures = /* @__PURE__ */ new Set();
4557
4787
  function warnStoreWriteFailure(error) {
@@ -4601,9 +4831,9 @@ function rethrowLockError(filePath, error, action = "save") {
4601
4831
  async function withOAuthStateLock(filePath, action, body) {
4602
4832
  let entered = false;
4603
4833
  try {
4604
- return await withSecretFileLock(filePath, async () => {
4834
+ return await withSecretFileLock(filePath, async (locked) => {
4605
4835
  entered = true;
4606
- return body();
4836
+ return body(locked);
4607
4837
  });
4608
4838
  } catch (error) {
4609
4839
  if (!entered) rethrowLockError(filePath, error, action);
@@ -4618,13 +4848,97 @@ var OAuthStateFileUnrecognizedError = class extends Error {
4618
4848
  this.name = "OAuthStateFileUnrecognizedError";
4619
4849
  }
4620
4850
  };
4621
- async function readDiskForMutation(filePath, action) {
4851
+ var SECRETS_NAMESPACE_KEY = "secretsNamespace";
4852
+ function parseSecretsNamespace(raw) {
4853
+ if (raw === null) return void 0;
4854
+ try {
4855
+ const parsed = JSON.parse(raw);
4856
+ if (typeof parsed !== "object" || parsed === null) return void 0;
4857
+ const value = parsed[SECRETS_NAMESPACE_KEY];
4858
+ return isValidSecretsNamespace(value) ? value : void 0;
4859
+ } catch {
4860
+ return void 0;
4861
+ }
4862
+ }
4863
+ function serializeOAuthFileBlob(snapshot, namespace) {
4864
+ if (namespace === void 0) return serializeOAuthPersistBlob(snapshot);
4865
+ return serializeStore({ [SECRETS_NAMESPACE_KEY]: namespace, ...snapshot });
4866
+ }
4867
+ function warnNamespaceCleanupFailure(error) {
4868
+ const reason = error instanceof Error ? error.message : String(error);
4869
+ const key = `namespace-cleanup:${reason}`;
4870
+ if (warnedStoreFailures.has(key)) return;
4871
+ warnedStoreFailures.add(key);
4872
+ console.warn(
4873
+ `[mcp-inspector] Could not remove legacy un-namespaced secret-store entries after scoping them to this state file (${reason}). This file uses the scoped copies, but another pre-namespace state file could still read the stale leftovers until it adopts or re-authorizes \u2014 and they will not be cleaned up automatically.`
4874
+ );
4875
+ }
4876
+ async function adoptSecretsNamespace(filePath, secretStore, locked) {
4622
4877
  const raw = await readStoreFile(filePath);
4623
- const parsed = parseOAuthPersistBlob(raw);
4624
- if (raw !== null && parsed === null) {
4625
- throw new OAuthStateFileUnrecognizedError(filePath, action);
4878
+ const existing = parseSecretsNamespace(raw);
4879
+ if (existing !== void 0) {
4880
+ if (locked) {
4881
+ await purgeSupersededNamespaces(filePath, secretStore, existing);
4882
+ }
4883
+ return existing;
4884
+ }
4885
+ const snapshot = parseOAuthPersistBlob(raw);
4886
+ if (raw !== null && snapshot === null) {
4887
+ throw new OAuthStateFileUnrecognizedError(filePath, "save");
4888
+ }
4889
+ if (locked) {
4890
+ await purgeSupersededNamespaces(filePath, secretStore, void 0);
4891
+ }
4892
+ const namespace = newSecretsNamespace();
4893
+ if (snapshot === null) return namespace;
4894
+ const moves = [
4895
+ ...Object.entries(snapshot.servers).map(([url, state]) => ({
4896
+ legacyId: oauthSecretServerId(url),
4897
+ scopedId: oauthSecretServerId(url, namespace),
4898
+ fields: serverSecretFields(state)
4899
+ })),
4900
+ ...Object.keys(snapshot.idpSessions).map((issuer) => ({
4901
+ legacyId: oauthIdpSecretServerId(issuer),
4902
+ scopedId: oauthIdpSecretServerId(issuer, namespace),
4903
+ fields: [IDP_SESSION_FIELD]
4904
+ }))
4905
+ ];
4906
+ if (moves.length === 0) return namespace;
4907
+ if (!locked) {
4908
+ throw new SecretStoreUnavailableError(
4909
+ `Could not save OAuth state: ${filePath} predates per-state-file secret namespaces, and migrating its secret-store entries needs the file lock, which is unavailable here (see the lock warning above). Migrating without it could lose credentials if two processes migrate at once. Nothing was changed; make the lock directory writable and retry \u2014 or, if you cannot, clear this file's stored OAuth state and re-authorize (clearing does not migrate, and the fresh state file mints its namespace without the lock).`
4910
+ );
4626
4911
  }
4627
- return parsed;
4912
+ await recordNamespaceKeys(
4913
+ filePath,
4914
+ secretStore,
4915
+ namespace,
4916
+ Object.keys(snapshot.servers),
4917
+ Object.keys(snapshot.idpSessions)
4918
+ );
4919
+ const touched = [];
4920
+ try {
4921
+ for (const { legacyId, scopedId, fields } of moves) {
4922
+ for (const field of fields) {
4923
+ const value = await secretStoreGetStrict(secretStore, legacyId, field);
4924
+ if (value === null) continue;
4925
+ touched.push({ serverId: scopedId, field, value: null });
4926
+ await secretStore.set(scopedId, field, value);
4927
+ }
4928
+ }
4929
+ await writeStoreFile(filePath, serializeOAuthFileBlob(snapshot, namespace));
4930
+ } catch (error) {
4931
+ await restoreSecretFields(secretStore, touched, warnRestoreFailure);
4932
+ throw error;
4933
+ }
4934
+ for (const { legacyId } of moves) {
4935
+ try {
4936
+ await secretStore.deleteAllForServer(legacyId);
4937
+ } catch (error) {
4938
+ warnNamespaceCleanupFailure(error);
4939
+ }
4940
+ }
4941
+ return namespace;
4628
4942
  }
4629
4943
  async function persistEntrySecrets(store, serverId, candidates, secrets, prior, allowDegrade) {
4630
4944
  const priorValue = new Map(prior.map(({ field, value }) => [field, value]));
@@ -4672,7 +4986,8 @@ function preserveNonDurableSecrets(diskSecrets, secrets) {
4672
4986
  async function writeOAuthSections(filePath, snapshot, sections, secretStore = defaultSecretStore()) {
4673
4987
  const policy = getPersistTokensPolicy();
4674
4988
  const durable = await secretStoreIsDurable(secretStore);
4675
- await withOAuthStateLock(filePath, "save", async () => {
4989
+ await withOAuthStateLock(filePath, "save", async (locked) => {
4990
+ let namespace = await adoptSecretsNamespace(filePath, secretStore, locked);
4676
4991
  const restoreBaseline = /* @__PURE__ */ new Map();
4677
4992
  const ourWrites = /* @__PURE__ */ new Map();
4678
4993
  const priorKey = (p) => `${p.serverId}\0${p.field}`;
@@ -4731,7 +5046,27 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
4731
5046
  const attemptWrites = /* @__PURE__ */ new Map();
4732
5047
  let written;
4733
5048
  try {
4734
- const disk = await readDiskForMutation(filePath, "save");
5049
+ const rawDisk = await readStoreFile(filePath);
5050
+ const disk = parseOAuthPersistBlob(rawDisk);
5051
+ if (rawDisk !== null && disk === null) {
5052
+ throw new OAuthStateFileUnrecognizedError(filePath, "save");
5053
+ }
5054
+ const diskNamespace = parseSecretsNamespace(rawDisk);
5055
+ if (diskNamespace !== void 0 && diskNamespace !== namespace) {
5056
+ let restoreFailure;
5057
+ await restoreSecretFields(
5058
+ secretStore,
5059
+ [...restoreBaseline.values()],
5060
+ (error) => {
5061
+ restoreFailure ??= error;
5062
+ }
5063
+ );
5064
+ if (restoreFailure !== void 0) throw restoreFailure;
5065
+ restoreBaseline.clear();
5066
+ ourWrites.clear();
5067
+ unconfirmed = null;
5068
+ namespace = diskNamespace;
5069
+ }
4735
5070
  const effective = sections ? {
4736
5071
  servers: sections.servers && [...new Set(sections.servers)],
4737
5072
  idpSessions: sections.idpSessions && [
@@ -4752,8 +5087,15 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
4752
5087
  ]
4753
5088
  };
4754
5089
  const merged = mergeOAuthSections(disk, snapshot, effective);
5090
+ await recordNamespaceKeys(
5091
+ filePath,
5092
+ secretStore,
5093
+ namespace,
5094
+ Object.keys(merged.servers),
5095
+ Object.keys(merged.idpSessions)
5096
+ );
4755
5097
  for (const url of effective.servers ?? []) {
4756
- const serverId = oauthSecretServerId(url);
5098
+ const serverId = oauthSecretServerId(url, namespace);
4757
5099
  const next = getOwnEntry(snapshot.servers, url);
4758
5100
  const candidates = [
4759
5101
  .../* @__PURE__ */ new Set([
@@ -4828,7 +5170,7 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
4828
5170
  }
4829
5171
  }
4830
5172
  for (const issuer of effective.idpSessions ?? []) {
4831
- const serverId = oauthIdpSecretServerId(issuer);
5173
+ const serverId = oauthIdpSecretServerId(issuer, namespace);
4832
5174
  const next = getOwnEntry(snapshot.idpSessions, issuer);
4833
5175
  const entryPrior = await snapshotSecretFields(secretStore, serverId, [
4834
5176
  IDP_SESSION_FIELD
@@ -4889,7 +5231,7 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
4889
5231
  value: secrets[IDP_SESSION_FIELD] ?? null
4890
5232
  });
4891
5233
  }
4892
- written = serializeOAuthPersistBlob(merged);
5234
+ written = serializeOAuthFileBlob(merged, namespace);
4893
5235
  await writeStoreFile(filePath, written);
4894
5236
  unconfirmed = { written, writes: attemptWrites };
4895
5237
  } catch (error) {
@@ -4913,36 +5255,42 @@ async function writeOAuthSections(filePath, snapshot, sections, secretStore = de
4913
5255
  );
4914
5256
  });
4915
5257
  }
4916
- function secretRequestsFor(snapshot) {
5258
+ function secretRequestsFor(snapshot, namespace) {
4917
5259
  const requests = [];
4918
5260
  for (const [url, state] of Object.entries(snapshot.servers)) {
4919
5261
  requests.push({
4920
- serverId: oauthSecretServerId(url),
5262
+ serverId: oauthSecretServerId(url, namespace),
4921
5263
  fields: serverSecretFields(state)
4922
5264
  });
4923
5265
  }
4924
5266
  for (const issuer of Object.keys(snapshot.idpSessions)) {
4925
5267
  requests.push({
4926
- serverId: oauthIdpSecretServerId(issuer),
5268
+ serverId: oauthIdpSecretServerId(issuer, namespace),
4927
5269
  fields: [IDP_SESSION_FIELD]
4928
5270
  });
4929
5271
  }
4930
5272
  return requests;
4931
5273
  }
4932
- async function joinSnapshot(snapshot, secretStore) {
4933
- const requests = secretRequestsFor(snapshot);
5274
+ async function joinSnapshot(snapshot, secretStore, namespace) {
5275
+ const requests = secretRequestsFor(snapshot, namespace);
4934
5276
  const values = requests.length > 0 ? await secretStoreGetManyStrict(secretStore, requests) : {};
4935
5277
  return {
4936
5278
  servers: Object.fromEntries(
4937
5279
  Object.entries(snapshot.servers).map(([url, state]) => [
4938
5280
  url,
4939
- joinServerOAuthState(state, values[oauthSecretServerId(url)] ?? {})
5281
+ joinServerOAuthState(
5282
+ state,
5283
+ values[oauthSecretServerId(url, namespace)] ?? {}
5284
+ )
4940
5285
  ])
4941
5286
  ),
4942
5287
  idpSessions: Object.fromEntries(
4943
5288
  Object.entries(snapshot.idpSessions).map(([issuer, session]) => [
4944
5289
  issuer,
4945
- joinIdpSession(session, values[oauthIdpSecretServerId(issuer)] ?? {})
5290
+ joinIdpSession(
5291
+ session,
5292
+ values[oauthIdpSecretServerId(issuer, namespace)] ?? {}
5293
+ )
4946
5294
  ])
4947
5295
  )
4948
5296
  };
@@ -4951,6 +5299,16 @@ async function migratePlaintextSecrets(filePath, secretStore) {
4951
5299
  const raw = await readStoreFile(filePath);
4952
5300
  const fresh = parseOAuthPersistBlob(raw);
4953
5301
  if (!fresh || !snapshotHasPlaintextSecrets(fresh)) return;
5302
+ const namespace = parseSecretsNamespace(raw);
5303
+ if (namespace !== void 0) {
5304
+ await recordNamespaceKeys(
5305
+ filePath,
5306
+ secretStore,
5307
+ namespace,
5308
+ Object.keys(fresh.servers),
5309
+ Object.keys(fresh.idpSessions)
5310
+ );
5311
+ }
4954
5312
  const migrateEntrySecrets = async (serverId, secrets) => {
4955
5313
  const absent = {};
4956
5314
  for (const [field, value] of Object.entries(secrets)) {
@@ -4967,44 +5325,57 @@ async function migratePlaintextSecrets(filePath, secretStore) {
4967
5325
  for (const [url, state] of Object.entries(fresh.servers)) {
4968
5326
  const split = splitServerOAuthState(state, "all");
4969
5327
  setOwnEntry(residue.servers, url, split.residue);
4970
- await migrateEntrySecrets(oauthSecretServerId(url), split.secrets);
5328
+ await migrateEntrySecrets(
5329
+ oauthSecretServerId(url, namespace),
5330
+ split.secrets
5331
+ );
4971
5332
  }
4972
5333
  for (const [issuer, session] of Object.entries(fresh.idpSessions)) {
4973
5334
  const split = splitIdpSession(session, "all");
4974
5335
  setOwnEntry(residue.idpSessions, issuer, split.residue);
4975
- await migrateEntrySecrets(oauthIdpSecretServerId(issuer), split.secrets);
5336
+ await migrateEntrySecrets(
5337
+ oauthIdpSecretServerId(issuer, namespace),
5338
+ split.secrets
5339
+ );
4976
5340
  }
4977
- const stripped = serializeOAuthPersistBlob(residue);
5341
+ const stripped = serializeOAuthFileBlob(residue, namespace);
4978
5342
  if (stripped !== raw) {
4979
5343
  await writeStoreFile(filePath, stripped);
4980
5344
  }
4981
5345
  }
4982
5346
  async function readOAuthStore(filePath, secretStore = defaultSecretStore()) {
4983
5347
  return withOAuthStateLock(filePath, "read", async () => {
4984
- let snapshot = parseOAuthPersistBlob(await readStoreFile(filePath));
5348
+ let raw = await readStoreFile(filePath);
5349
+ let snapshot = parseOAuthPersistBlob(raw);
4985
5350
  if (snapshot === null) return null;
4986
5351
  if (snapshotHasPlaintextSecrets(snapshot) && await secretStoreIsDurable(secretStore)) {
4987
5352
  try {
4988
5353
  await migratePlaintextSecrets(filePath, secretStore);
4989
- snapshot = parseOAuthPersistBlob(await readStoreFile(filePath)) ?? snapshot;
5354
+ raw = await readStoreFile(filePath);
5355
+ snapshot = parseOAuthPersistBlob(raw) ?? snapshot;
4990
5356
  } catch (error) {
4991
5357
  warnMigrationFailure(error);
4992
5358
  }
4993
5359
  }
4994
- return joinSnapshot(snapshot, secretStore);
5360
+ return joinSnapshot(snapshot, secretStore, parseSecretsNamespace(raw));
4995
5361
  });
4996
5362
  }
4997
5363
  async function removeOAuthStore(filePath, secretStore = defaultSecretStore()) {
4998
- await withOAuthStateLock(filePath, "remove", async () => {
4999
- const snapshot = await readDiskForMutation(filePath, "remove");
5364
+ await withOAuthStateLock(filePath, "remove", async (locked) => {
5365
+ const rawBlob = await readStoreFile(filePath);
5366
+ const snapshot = parseOAuthPersistBlob(rawBlob);
5367
+ if (rawBlob !== null && snapshot === null) {
5368
+ throw new OAuthStateFileUnrecognizedError(filePath, "remove");
5369
+ }
5000
5370
  if (snapshot) {
5371
+ const namespace = parseSecretsNamespace(rawBlob);
5001
5372
  const targets = [
5002
5373
  ...Object.entries(snapshot.servers).map(([url, state]) => ({
5003
- id: oauthSecretServerId(url),
5374
+ id: oauthSecretServerId(url, namespace),
5004
5375
  fields: serverSecretFields(state)
5005
5376
  })),
5006
5377
  ...Object.keys(snapshot.idpSessions).map((issuer) => ({
5007
- id: oauthIdpSecretServerId(issuer),
5378
+ id: oauthIdpSecretServerId(issuer, namespace),
5008
5379
  fields: [IDP_SESSION_FIELD]
5009
5380
  }))
5010
5381
  ];
@@ -5028,6 +5399,9 @@ async function removeOAuthStore(filePath, secretStore = defaultSecretStore()) {
5028
5399
  } else {
5029
5400
  await deleteStoreFile(filePath);
5030
5401
  }
5402
+ if (locked) {
5403
+ await purgeSupersededNamespaces(filePath, secretStore, void 0);
5404
+ }
5031
5405
  });
5032
5406
  }
5033
5407
 
@@ -5323,7 +5697,7 @@ var RemoteSession = class _RemoteSession {
5323
5697
  * `auth_challenge` or `ok: true` only after the MCP round-trip (or auth error).
5324
5698
  */
5325
5699
  waitForRequestResponse(requestId, timeoutMs = 6e4) {
5326
- return new Promise((resolve9, reject) => {
5700
+ return new Promise((resolve10, reject) => {
5327
5701
  let timer;
5328
5702
  const arm = () => {
5329
5703
  if (timeoutMs <= 0) return;
@@ -5346,7 +5720,7 @@ var RemoteSession = class _RemoteSession {
5346
5720
  this.requestWaits.set(requestId, {
5347
5721
  resolve: () => {
5348
5722
  clear();
5349
- resolve9();
5723
+ resolve10();
5350
5724
  },
5351
5725
  reject: (error) => {
5352
5726
  clear();
@@ -5869,13 +6243,13 @@ function closeAbortedStream(stream) {
5869
6243
  }
5870
6244
  async function primeAndHoldSseStream(stream, cleanup) {
5871
6245
  let done = false;
5872
- const aborted = new Promise((resolve9) => {
6246
+ const aborted = new Promise((resolve10) => {
5873
6247
  stream.onAbort(() => {
5874
6248
  if (done) return;
5875
6249
  done = true;
5876
6250
  cleanup();
5877
6251
  closeAbortedStream(stream);
5878
- resolve9();
6252
+ resolve10();
5879
6253
  });
5880
6254
  });
5881
6255
  await stream.write(SSE_PRIMING_COMMENT);
@@ -6364,7 +6738,7 @@ function createRemoteApp(options) {
6364
6738
  });
6365
6739
  });
6366
6740
  if (session.isTransportDead()) {
6367
- await new Promise((resolve9) => setTimeout(resolve9, 0));
6741
+ await new Promise((resolve10) => setTimeout(resolve10, 0));
6368
6742
  session.clearEventConsumer();
6369
6743
  sessions.delete(sessionId);
6370
6744
  return;
@@ -7664,6 +8038,40 @@ function injectAuthToken(html, token) {
7664
8038
  return script + html;
7665
8039
  }
7666
8040
 
8041
+ // server/health.ts
8042
+ var HEALTH_PATH = "/healthz";
8043
+ var HEALTH_BODY = Object.freeze({
8044
+ status: "ok"
8045
+ });
8046
+ var HEALTH_HEADERS = Object.freeze({
8047
+ "Content-Type": "application/json; charset=utf-8",
8048
+ "Cache-Control": "no-store"
8049
+ });
8050
+ var HEALTH_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
8051
+ function isHealthRequest(method, url) {
8052
+ if (!method || !HEALTH_METHODS.has(method.toUpperCase())) return false;
8053
+ const path6 = (url ?? "").split(/[?#]/, 1)[0];
8054
+ return path6 === HEALTH_PATH;
8055
+ }
8056
+ function healthBodyFor(method) {
8057
+ return method.toUpperCase() === "HEAD" ? null : JSON.stringify(HEALTH_BODY);
8058
+ }
8059
+ function healthResponse(method = "GET") {
8060
+ return new Response(healthBodyFor(method), {
8061
+ status: 200,
8062
+ headers: { ...HEALTH_HEADERS }
8063
+ });
8064
+ }
8065
+ function handleNodeHealthRequest(req, res) {
8066
+ const { method } = req;
8067
+ if (method === void 0 || !isHealthRequest(method, req.url)) return false;
8068
+ res.writeHead(200, { ...HEALTH_HEADERS });
8069
+ const body = healthBodyFor(method);
8070
+ if (body === null) res.end();
8071
+ else res.end(body);
8072
+ return true;
8073
+ }
8074
+
7667
8075
  // server/vite-hono-plugin.ts
7668
8076
  function honoMiddlewarePlugin(config) {
7669
8077
  let resolvedAuthToken = "";
@@ -7765,6 +8173,9 @@ function honoMiddlewarePlugin(config) {
7765
8173
  const honoMiddleware = async (req, res, next) => {
7766
8174
  try {
7767
8175
  const pathname = req.url || "";
8176
+ if (handleNodeHealthRequest(req, res)) {
8177
+ return;
8178
+ }
7768
8179
  if (!pathname.startsWith("/api")) {
7769
8180
  return next();
7770
8181
  }
@@ -7784,10 +8195,10 @@ function honoMiddlewarePlugin(config) {
7784
8195
  if (req.method !== "GET" && req.method !== "HEAD") {
7785
8196
  const chunks = [];
7786
8197
  req.on("data", (chunk) => chunks.push(chunk));
7787
- await new Promise((resolve9) => {
7788
- req.once("end", () => resolve9());
7789
- req.once("error", () => resolve9());
7790
- req.once("close", () => resolve9());
8198
+ await new Promise((resolve10) => {
8199
+ req.once("end", () => resolve10());
8200
+ req.once("error", () => resolve10());
8201
+ req.once("close", () => resolve10());
7791
8202
  });
7792
8203
  if (chunks.length > 0) {
7793
8204
  init.body = Buffer.concat(chunks);
@@ -7829,10 +8240,10 @@ function honoMiddlewarePlugin(config) {
7829
8240
  while (true) {
7830
8241
  const { done, value } = await reader.read();
7831
8242
  if (done || clientGone || res.destroyed) break;
7832
- await new Promise((resolve9, reject) => {
8243
+ await new Promise((resolve10, reject) => {
7833
8244
  res.write(
7834
8245
  Buffer.from(value),
7835
- (err) => err ? reject(err) : resolve9()
8246
+ (err) => err ? reject(err) : resolve10()
7836
8247
  );
7837
8248
  });
7838
8249
  }
@@ -8129,7 +8540,7 @@ function vitestSharedPaths(clientDir) {
8129
8540
  // server/start-vite-dev-server.ts
8130
8541
  var __dirname2 = dirname7(fileURLToPath4(import.meta.url));
8131
8542
  async function startViteDevServer(config) {
8132
- const root = resolve6(join7(__dirname2, ".."));
8543
+ const root = resolve7(join7(__dirname2, ".."));
8133
8544
  clearViteDepsCache(root);
8134
8545
  const { repoRoot, sharedAliases, sharedDedupe, nodeModulesAliases } = vitestSharedPaths(root);
8135
8546
  const inlineConfig = {
@@ -8222,6 +8633,7 @@ async function startHonoServer(config) {
8222
8633
  secretStorageResolver: getSecretStorageInfo
8223
8634
  });
8224
8635
  const app = new Hono2();
8636
+ app.get(HEALTH_PATH, (c) => healthResponse(c.req.method));
8225
8637
  app.use("/api/*", async (c) => {
8226
8638
  return apiApp.fetch(c.req.raw);
8227
8639
  });
@@ -8289,8 +8701,8 @@ async function startHonoServer(config) {
8289
8701
  if ("closeAllConnections" in httpServer) {
8290
8702
  httpServer.closeAllConnections();
8291
8703
  }
8292
- await new Promise((resolve9, reject) => {
8293
- httpServer.close((err) => err ? reject(err) : resolve9());
8704
+ await new Promise((resolve10, reject) => {
8705
+ httpServer.close((err) => err ? reject(err) : resolve10());
8294
8706
  });
8295
8707
  }
8296
8708
  };
@@ -8333,7 +8745,7 @@ function ensureWebBuild(webRoot, distRoot, deps = {}) {
8333
8745
  var __dirname4 = dirname9(fileURLToPath6(import.meta.url));
8334
8746
  function ensureStdioCwd(config) {
8335
8747
  if ((config.type === "stdio" || config.type === void 0) && config.command && !config.cwd) {
8336
- return { ...config, cwd: resolve7(process.cwd()) };
8748
+ return { ...config, cwd: resolve8(process.cwd()) };
8337
8749
  }
8338
8750
  return config;
8339
8751
  }
@@ -8396,7 +8808,7 @@ async function runWeb(argv) {
8396
8808
  "Note: --server has no effect on the web UI yet; it lists every server in the catalog."
8397
8809
  );
8398
8810
  }
8399
- mcpConfigPath = resolve7(process.cwd(), catalogPath);
8811
+ mcpConfigPath = resolve8(process.cwd(), catalogPath);
8400
8812
  writable = true;
8401
8813
  } else if (hasConfig) {
8402
8814
  if (opts.server) {
@@ -8404,7 +8816,7 @@ async function runWeb(argv) {
8404
8816
  "Note: --server has no effect on the web UI yet; it lists every server in the file."
8405
8817
  );
8406
8818
  }
8407
- const resolvedConfigPath = resolve7(process.cwd(), opts.config);
8819
+ const resolvedConfigPath = resolve8(process.cwd(), opts.config);
8408
8820
  try {
8409
8821
  resolveServerConfigs({ configPath: resolvedConfigPath }, "multi");
8410
8822
  } catch (err) {
@@ -8512,7 +8924,7 @@ async function runWeb(argv) {
8512
8924
 
8513
8925
  // src/index.ts
8514
8926
  var __filename2 = fileURLToPath7(import.meta.url);
8515
- var isMain = process.argv[1] !== void 0 && resolve8(process.argv[1]) === resolve8(__filename2);
8927
+ var isMain = process.argv[1] !== void 0 && resolve9(process.argv[1]) === resolve9(__filename2);
8516
8928
  if (isMain) {
8517
8929
  runWeb(process.argv).then((code) => process.exit(code ?? 0)).catch((e) => {
8518
8930
  console.error(e);