@mcp-use/client 2.0.0-beta.9 → 2.0.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +18 -19
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/auth/browser.d.ts +62 -6
  4. package/dist/auth/browser.d.ts.map +1 -1
  5. package/dist/auth/callback.d.ts.map +1 -1
  6. package/dist/auth/flow.d.ts.map +1 -1
  7. package/dist/auth/node.d.ts +115 -5
  8. package/dist/auth/node.d.ts.map +1 -1
  9. package/dist/auth/session-store.d.ts +7 -1
  10. package/dist/auth/session-store.d.ts.map +1 -1
  11. package/dist/auth/storage.d.ts +12 -3
  12. package/dist/auth/storage.d.ts.map +1 -1
  13. package/dist/code-mode/executor-e2b.d.ts.map +1 -1
  14. package/dist/core/base.d.ts +4 -8
  15. package/dist/core/base.d.ts.map +1 -1
  16. package/dist/core/browser.d.ts +14 -2
  17. package/dist/core/browser.d.ts.map +1 -1
  18. package/dist/core/config.d.ts +82 -20
  19. package/dist/core/config.d.ts.map +1 -1
  20. package/dist/core/node.d.ts +7 -10
  21. package/dist/core/node.d.ts.map +1 -1
  22. package/dist/core/session.d.ts +102 -25
  23. package/dist/core/session.d.ts.map +1 -1
  24. package/dist/index-browser.d.ts +1 -0
  25. package/dist/index-browser.d.ts.map +1 -1
  26. package/dist/index-browser.js +568 -163
  27. package/dist/index-browser.js.map +1 -1
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +410 -103
  31. package/dist/index.js.map +1 -1
  32. package/dist/react/McpClientProvider.d.ts +22 -10
  33. package/dist/react/McpClientProvider.d.ts.map +1 -1
  34. package/dist/react/index.d.ts +5 -2
  35. package/dist/react/index.d.ts.map +1 -1
  36. package/dist/react/index.js +1090 -352
  37. package/dist/react/index.js.map +1 -1
  38. package/dist/react/rpc-logger.d.ts +5 -0
  39. package/dist/react/rpc-logger.d.ts.map +1 -1
  40. package/dist/react/storage.d.ts +57 -10
  41. package/dist/react/storage.d.ts.map +1 -1
  42. package/dist/react/token-expiry.d.ts +9 -0
  43. package/dist/react/token-expiry.d.ts.map +1 -0
  44. package/dist/react/types.d.ts +134 -22
  45. package/dist/react/types.d.ts.map +1 -1
  46. package/dist/react/useMcp-helpers.d.ts.map +1 -1
  47. package/dist/react/useMcp-operations.d.ts +24 -6
  48. package/dist/react/useMcp-operations.d.ts.map +1 -1
  49. package/dist/react/useMcp.d.ts.map +1 -1
  50. package/dist/react/useMcpServerQueues.d.ts +36 -9
  51. package/dist/react/useMcpServerQueues.d.ts.map +1 -1
  52. package/dist/react/view/ViewRenderer.d.ts +12 -4
  53. package/dist/react/view/ViewRenderer.d.ts.map +1 -1
  54. package/dist/react/view/ext-apps-bridge.d.ts +1 -1
  55. package/dist/react/view/ext-apps-bridge.d.ts.map +1 -1
  56. package/dist/react/view/inject-openai-file-apis.d.ts.map +1 -1
  57. package/dist/react/view/parse-custom-props.d.ts +8 -0
  58. package/dist/react/view/parse-custom-props.d.ts.map +1 -1
  59. package/dist/react/view/resolve-view-resource.d.ts +10 -0
  60. package/dist/react/view/resolve-view-resource.d.ts.map +1 -1
  61. package/dist/react/view/sandbox-blob-url.d.ts +2 -0
  62. package/dist/react/view/sandbox-blob-url.d.ts.map +1 -1
  63. package/dist/react/view/types.d.ts +111 -4
  64. package/dist/react/view/types.d.ts.map +1 -1
  65. package/dist/react/view/view-detection.d.ts +18 -0
  66. package/dist/react/view/view-detection.d.ts.map +1 -1
  67. package/dist/react/view/view-host-policy.d.ts +61 -0
  68. package/dist/react/view/view-host-policy.d.ts.map +1 -0
  69. package/dist/sandbox.d.ts +2 -0
  70. package/dist/sandbox.d.ts.map +1 -0
  71. package/dist/sandbox.js +283 -0
  72. package/dist/sandbox.js.map +1 -0
  73. package/dist/telemetry/events.d.ts.map +1 -1
  74. package/dist/telemetry/tel-fetch.d.ts.map +1 -1
  75. package/dist/telemetry/telemetry.d.ts +5 -1
  76. package/dist/telemetry/telemetry.d.ts.map +1 -1
  77. package/dist/transport/base.d.ts +169 -34
  78. package/dist/transport/base.d.ts.map +1 -1
  79. package/dist/transport/connection-manager.d.ts +5 -1
  80. package/dist/transport/connection-manager.d.ts.map +1 -1
  81. package/dist/transport/http.d.ts +51 -2
  82. package/dist/transport/http.d.ts.map +1 -1
  83. package/dist/transport/stdio.d.ts +29 -1
  84. package/dist/transport/stdio.d.ts.map +1 -1
  85. package/dist/utils/elicitation.d.ts +4 -2
  86. package/dist/utils/elicitation.d.ts.map +1 -1
  87. package/dist/utils/logging.d.ts +1 -0
  88. package/dist/utils/logging.d.ts.map +1 -1
  89. package/dist/utils/version.d.ts +6 -0
  90. package/dist/utils/version.d.ts.map +1 -1
  91. package/package.json +9 -3
package/dist/index.js CHANGED
@@ -209,6 +209,11 @@ var init_base = __esm({
209
209
  notificationHandlers = [];
210
210
  rootsCache = [];
211
211
  activeProgressHandlers = /* @__PURE__ */ new Set();
212
+ /**
213
+ * Creates a connector with shared SDK and callback options.
214
+ *
215
+ * @param opts - Connector initialization options.
216
+ */
212
217
  constructor(opts = {}) {
213
218
  this.opts = opts;
214
219
  if (opts.roots) {
@@ -391,7 +396,9 @@ var init_base = __esm({
391
396
  }
392
397
  }
393
398
  /**
394
- * Get the current roots.
399
+ * Returns the roots currently advertised to the server.
400
+ *
401
+ * @returns A copy of the configured roots.
395
402
  */
396
403
  getRoots() {
397
404
  return [...this.rootsCache];
@@ -460,7 +467,11 @@ var init_base = __esm({
460
467
  "setupElicitationHandler: Elicitation handler registered successfully"
461
468
  );
462
469
  }
463
- /** Disconnect and release resources. */
470
+ /**
471
+ * Disconnects the SDK client and releases transport resources.
472
+ *
473
+ * @returns A promise that resolves after cleanup completes.
474
+ */
464
475
  async disconnect() {
465
476
  if (!this.connected) {
466
477
  logger.debug("Not connected to MCP implementation");
@@ -471,7 +482,7 @@ var init_base = __esm({
471
482
  this.connected = false;
472
483
  logger.debug("Disconnected from MCP implementation");
473
484
  }
474
- /** Check if the client is connected */
485
+ /** Whether an SDK client currently exists for this connector. */
475
486
  get isClientConnected() {
476
487
  return this.client != null;
477
488
  }
@@ -481,6 +492,10 @@ var init_base = __esm({
481
492
  * In the SDK, `Client.connect(transport)` automatically performs the
482
493
  * protocol‑level `initialize` handshake, so we only need to cache the list of
483
494
  * tools and expose some server info.
495
+ *
496
+ * @param defaultRequestOptions - Options used while fetching the initial tool list.
497
+ * @returns The capabilities advertised by the server.
498
+ * @throws When {@link BaseConnector.connect} has not completed.
484
499
  */
485
500
  async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
486
501
  if (!this.client) {
@@ -518,18 +533,22 @@ var init_base = __esm({
518
533
  logger.debug("Server info:", serverInfo);
519
534
  return capabilities;
520
535
  }
521
- /** Lazily expose the cached tools list. */
536
+ /**
537
+ * Returns the tool list cached during initialization.
538
+ *
539
+ * @throws When {@link BaseConnector.initialize} has not completed.
540
+ */
522
541
  get tools() {
523
542
  if (!this.toolsCache) {
524
543
  throw new Error("MCP client is not initialized; call initialize() first");
525
544
  }
526
545
  return this.toolsCache;
527
546
  }
528
- /** Expose cached server capabilities. */
547
+ /** Capabilities cached during initialization, or an empty object. */
529
548
  get serverCapabilities() {
530
549
  return this.capabilitiesCache || {};
531
550
  }
532
- /** Expose cached server info. */
551
+ /** Server identity cached during initialization, or `null`. */
533
552
  get serverInfo() {
534
553
  return this.serverInfoCache;
535
554
  }
@@ -550,7 +569,15 @@ var init_base = __esm({
550
569
  get negotiatedProtocolVersion() {
551
570
  return this.client?.getNegotiatedProtocolVersion?.();
552
571
  }
553
- /** Call a tool on the server. */
572
+ /**
573
+ * Calls a tool on the connected server.
574
+ *
575
+ * @param name - Tool name.
576
+ * @param args - Tool arguments.
577
+ * @param options - Per-request timeout, cancellation, and progress options.
578
+ * @returns The tool result returned by the server.
579
+ * @throws When the connector is not connected or the tool call fails.
580
+ */
554
581
  async callTool(name, args, options) {
555
582
  if (!this.client) {
556
583
  throw new Error("MCP client is not connected");
@@ -675,7 +702,13 @@ var init_base = __esm({
675
702
  );
676
703
  return result;
677
704
  }
678
- /** Read a resource by URI. */
705
+ /**
706
+ * Reads a resource by URI.
707
+ *
708
+ * @param uri - Resource URI to read.
709
+ * @param options - Per-request options.
710
+ * @returns The resource contents returned by the server.
711
+ */
679
712
  async readResource(uri, options) {
680
713
  if (!this.client) {
681
714
  throw new Error("MCP client is not connected");
@@ -710,6 +743,11 @@ var init_base = __esm({
710
743
  logger.debug(`Unsubscribing from resource: ${uri}`);
711
744
  return await this.client.unsubscribeResource({ uri }, options);
712
745
  }
746
+ /**
747
+ * Lists prompts exposed by the server.
748
+ *
749
+ * @returns The prompt list, or an empty list when prompts are unsupported.
750
+ */
713
751
  async listPrompts() {
714
752
  if (!this.client) {
715
753
  throw new Error("MCP client is not connected");
@@ -730,6 +768,13 @@ var init_base = __esm({
730
768
  throw err;
731
769
  }
732
770
  }
771
+ /**
772
+ * Gets a prompt with the supplied arguments.
773
+ *
774
+ * @param name - Prompt name.
775
+ * @param args - Prompt arguments.
776
+ * @returns The rendered prompt returned by the server.
777
+ */
733
778
  async getPrompt(name, args) {
734
779
  if (!this.client) {
735
780
  throw new Error("MCP client is not connected");
@@ -737,7 +782,14 @@ var init_base = __esm({
737
782
  logger.debug(`Getting prompt ${name}`);
738
783
  return await this.client.getPrompt({ name, arguments: args });
739
784
  }
740
- /** Send a raw request through the client. */
785
+ /**
786
+ * Sends a raw, potentially non-standard request through the SDK client.
787
+ *
788
+ * @param method - JSON-RPC method name.
789
+ * @param params - Request parameters. Defaults to an empty object.
790
+ * @param options - Per-request options.
791
+ * @returns The unvalidated result returned by the server.
792
+ */
741
793
  async request(method, params = null, options) {
742
794
  if (!this.client) {
743
795
  throw new Error("MCP client is not connected");
@@ -802,6 +854,8 @@ var init_connection_manager = __esm({
802
854
  _connection = null;
803
855
  _task = null;
804
856
  _abortController = null;
857
+ _startPromise = null;
858
+ _stopPromise = null;
805
859
  constructor() {
806
860
  this.reset();
807
861
  }
@@ -811,10 +865,21 @@ var init_connection_manager = __esm({
811
865
  * @returns The established connection.
812
866
  * @throws If the connection cannot be established.
813
867
  */
814
- async start() {
868
+ start() {
869
+ if (this._stopPromise) {
870
+ return this._stopPromise.then(() => this.start());
871
+ }
872
+ if (this._startPromise) return this._startPromise;
815
873
  this.reset();
816
874
  logger.debug(`Starting ${this.constructor.name}`);
817
875
  this._task = this.connectionTask();
876
+ this._startPromise = this.waitUntilReady().catch((error) => {
877
+ this._startPromise = null;
878
+ throw error;
879
+ });
880
+ return this._startPromise;
881
+ }
882
+ async waitUntilReady() {
818
883
  await this._readyPromise;
819
884
  if (this._exception) {
820
885
  throw this._exception;
@@ -827,7 +892,18 @@ var init_connection_manager = __esm({
827
892
  /**
828
893
  * Stop the connection manager and close the connection.
829
894
  */
830
- async stop() {
895
+ stop() {
896
+ if (this._stopPromise) return this._stopPromise;
897
+ if (!this._task) return Promise.resolve();
898
+ const trackedStop = this.stopTask().finally(() => {
899
+ if (this._stopPromise === trackedStop) {
900
+ this._stopPromise = null;
901
+ }
902
+ });
903
+ this._stopPromise = trackedStop;
904
+ return trackedStop;
905
+ }
906
+ async stopTask() {
831
907
  if (this._task && this._abortController) {
832
908
  logger.debug(`Cancelling ${this.constructor.name} task`);
833
909
  this._abortController.abort();
@@ -842,6 +918,8 @@ var init_connection_manager = __esm({
842
918
  }
843
919
  }
844
920
  await this._donePromise;
921
+ this._task = null;
922
+ this._startPromise = null;
845
923
  logger.debug(`${this.constructor.name} task completed`);
846
924
  }
847
925
  /**
@@ -933,6 +1011,11 @@ var init_stdio = __esm({
933
1011
  errlog;
934
1012
  clientInfo;
935
1013
  protocolNegotiation;
1014
+ /**
1015
+ * Creates a stdio connector.
1016
+ *
1017
+ * @param options - Process launch, client identity, and shared connector options.
1018
+ */
936
1019
  constructor({
937
1020
  command = "npx",
938
1021
  args = [],
@@ -952,7 +1035,11 @@ var init_stdio = __esm({
952
1035
  this.cwd = rest.cwd;
953
1036
  this.protocolNegotiation = rest.protocolNegotiation ?? "legacy";
954
1037
  }
955
- /** Establish connection to the MCP implementation. */
1038
+ /**
1039
+ * Starts the child process and establishes an MCP connection.
1040
+ *
1041
+ * @returns A promise that resolves after protocol negotiation completes.
1042
+ */
956
1043
  async connect() {
957
1044
  if (this.connected) {
958
1045
  logger.debug("Already connected to MCP implementation");
@@ -960,20 +1047,12 @@ var init_stdio = __esm({
960
1047
  }
961
1048
  logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
962
1049
  try {
963
- let mergedEnv;
964
- if (this.env) {
965
- mergedEnv = {};
966
- for (const [key, value] of Object.entries(process2.env)) {
967
- if (value !== void 0) {
968
- mergedEnv[key] = value;
969
- }
970
- }
971
- Object.assign(mergedEnv, this.env);
972
- }
973
1050
  const serverParams = {
974
1051
  command: this.command,
975
1052
  args: this.args,
976
- env: mergedEnv,
1053
+ // The SDK layers explicit values over getDefaultEnvironment(). Passing
1054
+ // the configured env through avoids exposing unrelated parent secrets.
1055
+ env: this.env,
977
1056
  cwd: this.cwd
978
1057
  };
979
1058
  this.connectionManager = new StdioConnectionManager(
@@ -1048,6 +1127,11 @@ var init_stdio = __esm({
1048
1127
  throw err;
1049
1128
  }
1050
1129
  }
1130
+ /**
1131
+ * Returns fields identifying the launched command and arguments.
1132
+ *
1133
+ * @returns Stdio connector identity metadata.
1134
+ */
1051
1135
  get publicIdentifier() {
1052
1136
  return {
1053
1137
  type: "stdio",
@@ -1059,6 +1143,12 @@ var init_stdio = __esm({
1059
1143
  serverParams;
1060
1144
  errlog;
1061
1145
  _transport = null;
1146
+ /**
1147
+ * Creates a connection manager for a local server process.
1148
+ *
1149
+ * @param serverParams - Process parameters passed to the SDK transport.
1150
+ * @param errlog - Destination for the child process's standard error stream.
1151
+ */
1062
1152
  constructor(serverParams, errlog = process2.stderr) {
1063
1153
  super();
1064
1154
  this.serverParams = serverParams;
@@ -1108,7 +1198,7 @@ init_connector_telemetry();
1108
1198
  init_logging();
1109
1199
 
1110
1200
  // src/utils/version.ts
1111
- var VERSION = "2.0.0-beta.8";
1201
+ var VERSION = "2.0.1-canary.0";
1112
1202
  function getPackageVersion() {
1113
1203
  return VERSION;
1114
1204
  }
@@ -1128,16 +1218,13 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
1128
1218
  return {
1129
1219
  // Core execution info
1130
1220
  execution_method: this.data.executionMethod,
1131
- query: this.data.query,
1132
1221
  query_length: this.data.query.length,
1133
1222
  success: this.data.success,
1134
1223
  // Agent configuration
1135
1224
  model_provider: this.data.modelProvider,
1136
1225
  model_name: this.data.modelName,
1137
1226
  server_count: this.data.serverCount,
1138
- server_identifiers: this.data.serverIdentifiers,
1139
1227
  total_tools_available: this.data.totalToolsAvailable,
1140
- tools_available_names: this.data.toolsAvailableNames,
1141
1228
  max_steps_configured: this.data.maxStepsConfigured,
1142
1229
  memory_enabled: this.data.memoryEnabled,
1143
1230
  use_server_manager: this.data.useServerManager,
@@ -1148,8 +1235,6 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
1148
1235
  // Execution results (always include, even if null)
1149
1236
  steps_taken: this.data.stepsTaken ?? null,
1150
1237
  tools_used_count: this.data.toolsUsedCount ?? null,
1151
- tools_used_names: this.data.toolsUsedNames ?? null,
1152
- response: this.data.response ?? null,
1153
1238
  response_length: this.data.response ? this.data.response.length : null,
1154
1239
  execution_time_ms: this.data.executionTimeMs ?? null,
1155
1240
  error_type: this.data.errorType ?? null,
@@ -1245,21 +1330,72 @@ async function telFetch(url, init) {
1245
1330
  }
1246
1331
  var POSTHOG_HOST = "https://eu.i.posthog.com";
1247
1332
  var POSTHOG_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI";
1248
- function capturePostHog(params) {
1249
- const host = params.host ?? POSTHOG_HOST;
1250
- const apiKey = params.apiKey ?? POSTHOG_API_KEY;
1251
- return telFetch(`${host}/i/v0/e/`, {
1252
- method: "POST",
1253
- headers: { "Content-Type": "application/json" },
1254
- keepalive: true,
1255
- body: JSON.stringify({
1333
+ var CONTENT_PROPERTY = /(^|_)(arguments?|args|body|command|headers?|location|message|query|response|secret|subject|token|uri|url|user_agent)(_|$)/i;
1334
+ var IDENTIFYING_PROPERTY = /(^|_)(server_identifiers?|server_names?|servers|tool_names?|tools_(available|used)_names)(_|$)/i;
1335
+ var AGGREGATE_PROPERTY = /(_count|_length|_duration(?:_ms)?|_time_ms|(^|_)num_[a-z0-9_]+)$/i;
1336
+ function normalizePropertyKey(key) {
1337
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_$]+/gi, "_").toLowerCase();
1338
+ }
1339
+ function sanitizeValue(value, seen) {
1340
+ if (Array.isArray(value)) {
1341
+ if (seen.has(value)) {
1342
+ throw new TypeError("Cyclic telemetry properties are not supported");
1343
+ }
1344
+ seen.add(value);
1345
+ const sanitized = value.map((item) => sanitizeValue(item, seen));
1346
+ seen.delete(value);
1347
+ return sanitized;
1348
+ }
1349
+ if (value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) {
1350
+ if (seen.has(value)) {
1351
+ throw new TypeError("Cyclic telemetry properties are not supported");
1352
+ }
1353
+ seen.add(value);
1354
+ const sanitized = sanitizeProperties(
1355
+ value,
1356
+ seen
1357
+ );
1358
+ seen.delete(value);
1359
+ return sanitized;
1360
+ }
1361
+ return value;
1362
+ }
1363
+ function sanitizeProperties(properties, seen = /* @__PURE__ */ new WeakSet()) {
1364
+ const sanitized = {};
1365
+ for (const [key, value] of Object.entries(properties)) {
1366
+ const normalizedKey = normalizePropertyKey(key);
1367
+ if (AGGREGATE_PROPERTY.test(normalizedKey)) {
1368
+ if (value === null || typeof value === "number") {
1369
+ sanitized[key] = value;
1370
+ }
1371
+ continue;
1372
+ }
1373
+ if (IDENTIFYING_PROPERTY.test(normalizedKey) || CONTENT_PROPERTY.test(normalizedKey)) {
1374
+ continue;
1375
+ }
1376
+ sanitized[key] = sanitizeValue(value, seen);
1377
+ }
1378
+ return sanitized;
1379
+ }
1380
+ async function capturePostHog(params) {
1381
+ try {
1382
+ const host = params.host ?? POSTHOG_HOST;
1383
+ const apiKey = params.apiKey ?? POSTHOG_API_KEY;
1384
+ const body = JSON.stringify({
1256
1385
  api_key: apiKey,
1257
1386
  event: params.event,
1258
1387
  distinct_id: params.distinctId,
1259
- properties: params.properties,
1388
+ properties: sanitizeProperties(params.properties),
1260
1389
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1261
- })
1262
- });
1390
+ });
1391
+ await telFetch(`${host}/i/v0/e/`, {
1392
+ method: "POST",
1393
+ headers: { "Content-Type": "application/json" },
1394
+ keepalive: true,
1395
+ body
1396
+ });
1397
+ } catch {
1398
+ }
1263
1399
  }
1264
1400
 
1265
1401
  // src/telemetry/telemetry.ts
@@ -1789,11 +1925,12 @@ async function completeOAuthFlow(provider, serverUrl, options = {}) {
1789
1925
  throw new Error(`Unexpected OAuth auth() result: ${result}`);
1790
1926
  }
1791
1927
  }
1792
- if (typeof flowProvider.getAuthorizationCode === "function") {
1793
- const code = await flowProvider.getAuthorizationCode();
1928
+ if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
1929
+ const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
1794
1930
  await auth(provider, {
1795
1931
  serverUrl,
1796
- authorizationCode: code,
1932
+ authorizationCode: response.code,
1933
+ ...response.iss !== void 0 ? { iss: response.iss } : {},
1797
1934
  fetchFn
1798
1935
  });
1799
1936
  return;
@@ -1807,6 +1944,8 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
1807
1944
  );
1808
1945
  }
1809
1946
  if (provider.useRedirectFlow) {
1947
+ await new Promise(() => {
1948
+ });
1810
1949
  return;
1811
1950
  }
1812
1951
  const tokensKey = provider.getKey?.("tokens");
@@ -1823,25 +1962,29 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
1823
1962
  } catch {
1824
1963
  }
1825
1964
  }
1826
- const result = await runAuthPopup({
1827
- popup: null,
1828
- state,
1829
- tokensKey,
1830
- timeoutMs
1831
- });
1832
- switch (result.kind) {
1833
- case "success":
1834
- return;
1835
- case "cancelled":
1836
- throw new Error("OAuth authentication was cancelled.");
1837
- case "timeout":
1838
- throw new Error(
1839
- `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
1840
- );
1841
- case "error":
1842
- throw new Error(result.error);
1843
- default:
1844
- throw new Error("Unexpected OAuth popup result");
1965
+ try {
1966
+ const result = await runAuthPopup({
1967
+ popup: null,
1968
+ state,
1969
+ tokensKey,
1970
+ timeoutMs
1971
+ });
1972
+ switch (result.kind) {
1973
+ case "success":
1974
+ return;
1975
+ case "cancelled":
1976
+ throw new Error("OAuth authentication was cancelled.");
1977
+ case "timeout":
1978
+ throw new Error(
1979
+ `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
1980
+ );
1981
+ case "error":
1982
+ throw new Error(result.error);
1983
+ default:
1984
+ throw new Error("Unexpected OAuth popup result");
1985
+ }
1986
+ } finally {
1987
+ provider.markFlowComplete?.();
1845
1988
  }
1846
1989
  }
1847
1990
 
@@ -2054,29 +2197,39 @@ var OAuthSessionStore = class _OAuthSessionStore {
2054
2197
  if (ctx) await this.store.set(this.credentialKey("tokens"), serialized);
2055
2198
  await this.store.remove(this.getKey("code_verifier"));
2056
2199
  await this.store.remove(this.getKey("last_auth_url"));
2200
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2057
2201
  }
2058
2202
  async clientInformation(ctx) {
2203
+ if (!this.allowClientSecret) {
2204
+ const registeredRedirectUri = await this.store.get(
2205
+ this.getKey("client_info_redirect_uri")
2206
+ );
2207
+ if (registeredRedirectUri !== this.redirectUrl) {
2208
+ await this.invalidateCredentials("registration");
2209
+ console.info(
2210
+ `[${this.storageKeyPrefix}] Re-registering browser OAuth client after its Inspector callback changed or could not be verified.`
2211
+ );
2212
+ return void 0;
2213
+ }
2214
+ }
2059
2215
  const stored = await this.readCredential("client_info", ctx);
2060
2216
  if (!stored) return void 0;
2061
2217
  const { key, value: clientInfo } = stored;
2062
2218
  try {
2063
2219
  if (!this.allowClientSecret && clientInfo.client_secret) {
2064
- await this.store.remove(key);
2065
- if (ctx) await this.store.remove(this.credentialKey("client_info"));
2220
+ await this.invalidateCredentials("registration");
2066
2221
  console.warn(
2067
- `[${this.storageKeyPrefix}] Removed OAuth client information containing a browser client_secret.`
2222
+ `[${this.storageKeyPrefix}] Recovered stale browser OAuth credentials containing a client_secret.`
2068
2223
  );
2069
2224
  return void 0;
2070
2225
  }
2071
2226
  const storedRedirectUris = Array.isArray(clientInfo.redirect_uris) ? clientInfo.redirect_uris : [];
2072
- const hasMatchingRedirect = storedRedirectUris.length === 0 || storedRedirectUris.includes(this.redirectUrl);
2227
+ const hasMatchingRedirect = storedRedirectUris.length === 0 && this.allowClientSecret || storedRedirectUris.includes(this.redirectUrl);
2073
2228
  if (!hasMatchingRedirect) {
2074
2229
  console.info(
2075
- `[${this.storageKeyPrefix}] Invalidating cached OAuth client info due to redirect URI mismatch.`
2230
+ `[${this.storageKeyPrefix}] Recovering cached OAuth credentials after a redirect URI change.`
2076
2231
  );
2077
- await this.store.remove(key);
2078
- await this.store.remove(this.credentialKey("tokens", ctx));
2079
- await this.store.remove(this.getKey("last_auth_url"));
2232
+ await this.invalidateCredentials("registration");
2080
2233
  return void 0;
2081
2234
  }
2082
2235
  return clientInfo;
@@ -2094,11 +2247,20 @@ var OAuthSessionStore = class _OAuthSessionStore {
2094
2247
  "Browser OAuth clients must be public clients; client_secret persistence is not allowed."
2095
2248
  );
2096
2249
  }
2097
- const serialized = JSON.stringify(clientInformation);
2250
+ const persistedClientInformation = !this.allowClientSecret && (!("redirect_uris" in clientInformation) || !Array.isArray(
2251
+ clientInformation.redirect_uris
2252
+ ) || clientInformation.redirect_uris.length === 0) ? { ...clientInformation, redirect_uris: [this.redirectUrl] } : clientInformation;
2253
+ const serialized = JSON.stringify(persistedClientInformation);
2098
2254
  await this.store.set(this.credentialKey("client_info", ctx), serialized);
2099
2255
  if (ctx) {
2100
2256
  await this.store.set(this.credentialKey("client_info"), serialized);
2101
2257
  }
2258
+ if (!this.allowClientSecret) {
2259
+ await this.store.set(
2260
+ this.getKey("client_info_redirect_uri"),
2261
+ this.redirectUrl
2262
+ );
2263
+ }
2102
2264
  }
2103
2265
  async saveCodeVerifier(codeVerifier) {
2104
2266
  await this.store.set(this.getKey("code_verifier"), codeVerifier);
@@ -2123,11 +2285,22 @@ var OAuthSessionStore = class _OAuthSessionStore {
2123
2285
  }
2124
2286
  };
2125
2287
  switch (scope) {
2288
+ case "registration":
2289
+ await removeCredentialKeys("tokens");
2290
+ await removeCredentialKeys("client_info");
2291
+ await this.store.remove(this.getKey("code_verifier"));
2292
+ await this.store.remove(this.getKey("last_auth_url"));
2293
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2294
+ await this.store.remove(this.getKey("client_info_redirect_uri"));
2295
+ await this.store.remove(this.getKey("token_endpoint"));
2296
+ break;
2126
2297
  case "all":
2127
2298
  await removeCredentialKeys("tokens");
2128
2299
  await removeCredentialKeys("client_info");
2129
2300
  await this.store.remove(this.getKey("code_verifier"));
2130
2301
  await this.store.remove(this.getKey("last_auth_url"));
2302
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2303
+ await this.store.remove(this.getKey("client_info_redirect_uri"));
2131
2304
  await this.store.remove(this.getKey("discovery_state"));
2132
2305
  await this.store.remove(this.getKey("token_endpoint"));
2133
2306
  break;
@@ -2177,7 +2350,7 @@ var OAuthSessionStore = class _OAuthSessionStore {
2177
2350
  */
2178
2351
  async storeAuthorizationState(authorizationUrl, opts = {}) {
2179
2352
  const state = globalThis.crypto.randomUUID();
2180
- const stateKey = `${this.storageKeyPrefix}:state_${state}`;
2353
+ const stateKey = `${this.storageKeyPrefix}_${this.serverUrlHash}_state_${state}`;
2181
2354
  const stateData = {
2182
2355
  serverUrlHash: this.serverUrlHash,
2183
2356
  expiry: Date.now() + 1e3 * 60 * 10,
@@ -2197,6 +2370,10 @@ var OAuthSessionStore = class _OAuthSessionStore {
2197
2370
  authorizationUrl.searchParams.set("state", state);
2198
2371
  const sanitizedAuthUrl = sanitizeUrl(authorizationUrl.toString());
2199
2372
  await this.store.set(stateKey, JSON.stringify(stateData));
2373
+ await this.store.set(
2374
+ this.getKey("last_auth_callback_url"),
2375
+ this.redirectUrl
2376
+ );
2200
2377
  await this.store.set(this.getKey("last_auth_url"), sanitizedAuthUrl);
2201
2378
  return sanitizedAuthUrl;
2202
2379
  }
@@ -2222,8 +2399,16 @@ var DEFAULT_PORT = 33418;
2222
2399
  var PORT_RANGE = 10;
2223
2400
  var DEFAULT_AUTH_TIMEOUT_MS2 = 5 * 6e4;
2224
2401
  var OAuthFlowError = class extends Error {
2402
+ /** OAuth or local-flow error code. */
2225
2403
  code;
2404
+ /** Optional human-readable error description. */
2226
2405
  description;
2406
+ /**
2407
+ * Creates an OAuth flow error.
2408
+ *
2409
+ * @param code - OAuth or local-flow error code.
2410
+ * @param description - Optional human-readable description.
2411
+ */
2227
2412
  constructor(code, description) {
2228
2413
  super(description ? `${code}: ${description}` : code);
2229
2414
  this.code = code;
@@ -2273,16 +2458,20 @@ h1{font-size:20px;margin:0 0 12px;color:#b00020}p{line-height:1.5}code{backgroun
2273
2458
  <p><code>${escapeHtml(err)}</code>${desc ? `: ${escapeHtml(desc)}` : ""}</p>
2274
2459
  <p>You can close this tab and return to your terminal.</p></body></html>`;
2275
2460
  var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2461
+ /** Protected MCP server URL associated with this provider. */
2276
2462
  serverUrl;
2463
+ /** Reserved localhost callback port. */
2277
2464
  port;
2278
2465
  session;
2279
2466
  kv;
2280
2467
  authTimeoutMs;
2281
2468
  openBrowserOverride;
2282
2469
  server = null;
2470
+ /** Provider authorization URL, exposed only through the local redirect route. */
2471
+ authorizationUrl = null;
2283
2472
  /** Currently in-flight deferred — used to prevent overlapping flows. */
2284
2473
  pending = null;
2285
- /** Latest deferred (settled or in-flight) what `getAuthorizationCode()` returns. */
2474
+ /** Latest deferred (settled or in-flight) for the loopback response. */
2286
2475
  lastFlow = null;
2287
2476
  pendingTimer = null;
2288
2477
  constructor(serverUrl, port, session, kv, options) {
@@ -2293,6 +2482,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2293
2482
  this.authTimeoutMs = options.authTimeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS2;
2294
2483
  this.openBrowserOverride = options.openBrowser;
2295
2484
  }
2485
+ /**
2486
+ * Creates a Node OAuth provider and reserves a localhost callback port.
2487
+ *
2488
+ * @param serverUrl - Protected MCP server URL.
2489
+ * @param options - OAuth metadata, storage, loopback, and browser options.
2490
+ * @returns A provider ready to participate in the SDK OAuth flow.
2491
+ */
2296
2492
  static async create(serverUrl, options = {}) {
2297
2493
  const serverUrlHash = OAuthSessionStore.hashString(serverUrl);
2298
2494
  const kv = options.kvStore ?? new FileKVStore(serverUrlHash, options.baseDir);
@@ -2325,48 +2521,100 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2325
2521
  return new _NodeOAuthClientProvider(serverUrl, port, session, kv, options);
2326
2522
  }
2327
2523
  // --- Identity passthroughs (parallel to BrowserOAuthClientProvider) ---
2524
+ /** Prefix used for persisted OAuth session keys. */
2328
2525
  get storageKeyPrefix() {
2329
2526
  return this.session.storageKeyPrefix;
2330
2527
  }
2528
+ /** Stable hash of the protected server URL used to namespace storage. */
2331
2529
  get serverUrlHash() {
2332
2530
  return this.session.serverUrlHash;
2333
2531
  }
2334
2532
  // --- SDK Interface (delegated to OAuthSessionStore) ---
2533
+ /** Loopback redirect URL registered for this provider. */
2335
2534
  get redirectUrl() {
2336
2535
  return this.session.redirectUrl;
2337
2536
  }
2537
+ /** OAuth client metadata presented during registration. */
2338
2538
  get clientMetadata() {
2339
2539
  return this.session.clientMetadata;
2340
2540
  }
2541
+ /** OAuth Client ID Metadata Document URL, when configured. */
2341
2542
  get clientMetadataUrl() {
2342
2543
  return this.session.clientMetadataUrl;
2343
2544
  }
2545
+ /**
2546
+ * Loads saved OAuth tokens.
2547
+ *
2548
+ * @param ctx - Optional client registration context.
2549
+ * @returns Saved tokens, or `undefined` when none exist.
2550
+ */
2344
2551
  tokens(ctx) {
2345
2552
  return this.session.tokens(ctx);
2346
2553
  }
2554
+ /**
2555
+ * Persists OAuth tokens.
2556
+ *
2557
+ * @param tokens - Tokens to save.
2558
+ * @param ctx - Optional client registration context.
2559
+ */
2347
2560
  saveTokens(tokens, ctx) {
2348
2561
  return this.session.saveTokens(tokens, ctx);
2349
2562
  }
2563
+ /**
2564
+ * Loads saved OAuth client registration information.
2565
+ *
2566
+ * @param ctx - Optional registration context.
2567
+ * @returns Saved registration information, or `undefined`.
2568
+ */
2350
2569
  clientInformation(ctx) {
2351
2570
  return this.session.clientInformation(ctx);
2352
2571
  }
2572
+ /**
2573
+ * Persists OAuth client registration information.
2574
+ *
2575
+ * @param info - Client information to save.
2576
+ * @param ctx - Optional registration context.
2577
+ */
2353
2578
  saveClientInformation(info, ctx) {
2354
2579
  return this.session.saveClientInformation(info, ctx);
2355
2580
  }
2581
+ /**
2582
+ * Loads the saved PKCE code verifier.
2583
+ *
2584
+ * @returns The saved verifier.
2585
+ */
2356
2586
  codeVerifier() {
2357
2587
  return this.session.codeVerifier();
2358
2588
  }
2589
+ /**
2590
+ * Persists a PKCE code verifier.
2591
+ *
2592
+ * @param codeVerifier - Verifier to save.
2593
+ */
2359
2594
  saveCodeVerifier(codeVerifier) {
2360
2595
  return this.session.saveCodeVerifier(codeVerifier);
2361
2596
  }
2597
+ /**
2598
+ * Invalidates selected persisted OAuth credentials.
2599
+ *
2600
+ * @param scope - Credential group to remove.
2601
+ */
2362
2602
  invalidateCredentials(scope) {
2363
2603
  return this.session.invalidateCredentials(scope);
2364
2604
  }
2365
- /** Persist OAuth discovery state (SEP-2352). Delegated to the session store. */
2605
+ /**
2606
+ * Persists OAuth discovery state.
2607
+ *
2608
+ * @param state - Discovery state to save.
2609
+ */
2366
2610
  saveDiscoveryState(state) {
2367
2611
  return this.session.saveDiscoveryState(state);
2368
2612
  }
2369
- /** Return previously saved OAuth discovery state, or `undefined`. */
2613
+ /**
2614
+ * Returns previously saved OAuth discovery state.
2615
+ *
2616
+ * @returns Saved discovery state, or `undefined`.
2617
+ */
2370
2618
  discoveryState() {
2371
2619
  return this.session.discoveryState();
2372
2620
  }
@@ -2374,6 +2622,10 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2374
2622
  * Bind the loopback server, set up the pending-code deferred, and ask the
2375
2623
  * platform to open the user's browser. Does NOT await the code; the
2376
2624
  * orchestrator awaits via `getAuthorizationCode()`.
2625
+ *
2626
+ * @param authorizationUrl - Authorization URL generated by the SDK.
2627
+ * @returns A promise that resolves once the loopback listener is ready and
2628
+ * the browser-open attempt completes.
2377
2629
  */
2378
2630
  async redirectToAuthorization(authorizationUrl) {
2379
2631
  if (this.pending) {
@@ -2385,6 +2637,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2385
2637
  authorizationUrl,
2386
2638
  { flowType: "redirect" }
2387
2639
  );
2640
+ this.authorizationUrl = sanitizedUrl;
2388
2641
  await this.startLoopback();
2389
2642
  this.pending = createDeferred();
2390
2643
  this.lastFlow = this.pending;
@@ -2399,8 +2652,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2399
2652
  );
2400
2653
  }, this.authTimeoutMs);
2401
2654
  const opener = this.openBrowserOverride ?? defaultOpener;
2655
+ const launcherUrl = `http://127.0.0.1:${this.port}/authorize`;
2402
2656
  try {
2403
- await opener(sanitizedUrl);
2657
+ await opener(launcherUrl);
2404
2658
  } catch (err) {
2405
2659
  console.error(
2406
2660
  `[mcp-use] Could not open browser automatically: ${err instanceof Error ? err.message : String(err)}`
@@ -2409,15 +2663,30 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2409
2663
  }
2410
2664
  /**
2411
2665
  * Resolves with the authorization code captured by the loopback callback.
2666
+ *
2667
+ * @remarks This compatibility method omits the RFC 9207 issuer. OAuth flow
2668
+ * orchestrators should use {@link getAuthorizationResponse} when available.
2412
2669
  * Must be called after `redirectToAuthorization()`. Returns the same
2413
2670
  * promise whether the callback has fired or not — callers may subscribe
2414
2671
  * before or after.
2672
+ *
2673
+ * @returns The authorization code received by the loopback callback.
2415
2674
  */
2416
2675
  getAuthorizationCode() {
2676
+ return this.getAuthorizationResponse().then((response) => response.code);
2677
+ }
2678
+ /**
2679
+ * Resolves with the authorization code and RFC 9207 issuer captured by the
2680
+ * loopback callback.
2681
+ *
2682
+ * @returns The loopback authorization response.
2683
+ * @throws When called before {@link NodeOAuthClientProvider.redirectToAuthorization}.
2684
+ */
2685
+ getAuthorizationResponse() {
2417
2686
  if (!this.lastFlow) {
2418
2687
  return Promise.reject(
2419
2688
  new Error(
2420
- "NodeOAuthClientProvider.getAuthorizationCode() called before redirectToAuthorization()"
2689
+ "NodeOAuthClientProvider.getAuthorizationResponse() called before redirectToAuthorization()"
2421
2690
  )
2422
2691
  );
2423
2692
  }
@@ -2425,6 +2694,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2425
2694
  }
2426
2695
  /**
2427
2696
  * Cancel an in-progress flow (timeout, SIGINT, etc.) and close the loopback.
2697
+ *
2698
+ * Pending calls to {@link NodeOAuthClientProvider.getAuthorizationResponse}
2699
+ * reject with an {@link OAuthFlowError} whose code is `"cancelled"`.
2428
2700
  */
2429
2701
  dispose() {
2430
2702
  if (this.pending) {
@@ -2433,7 +2705,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2433
2705
  this.stopLoopback();
2434
2706
  }
2435
2707
  }
2436
- /** Best-effort port for tests / status output. */
2708
+ /** Local callback port, useful for status output and tests. */
2437
2709
  get callbackPort() {
2438
2710
  return this.port;
2439
2711
  }
@@ -2471,12 +2743,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2471
2743
  this.server.close();
2472
2744
  this.server = null;
2473
2745
  }
2746
+ this.authorizationUrl = null;
2474
2747
  }
2475
- resolvePending(code) {
2748
+ resolvePending(response) {
2476
2749
  const p = this.pending;
2477
2750
  this.pending = null;
2478
2751
  this.stopLoopback();
2479
- p?.resolve(code);
2752
+ p?.resolve(response);
2480
2753
  }
2481
2754
  rejectPending(err) {
2482
2755
  const p = this.pending;
@@ -2486,6 +2759,19 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2486
2759
  }
2487
2760
  handleCallback(rawUrl, res) {
2488
2761
  const url = new URL(rawUrl, `http://127.0.0.1:${this.port}`);
2762
+ if (url.pathname === "/authorize") {
2763
+ if (this.authorizationUrl === null || this.pending === null) {
2764
+ res.statusCode = 410;
2765
+ res.end("Authorization flow is not active");
2766
+ return;
2767
+ }
2768
+ res.statusCode = 302;
2769
+ res.setHeader("location", this.authorizationUrl);
2770
+ res.setHeader("cache-control", "no-store");
2771
+ res.setHeader("referrer-policy", "no-referrer");
2772
+ res.end();
2773
+ return;
2774
+ }
2489
2775
  if (url.pathname !== "/callback") {
2490
2776
  res.statusCode = 404;
2491
2777
  res.end("Not Found");
@@ -2493,6 +2779,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2493
2779
  }
2494
2780
  const code = url.searchParams.get("code");
2495
2781
  const state = url.searchParams.get("state");
2782
+ const iss = url.searchParams.get("iss") ?? void 0;
2496
2783
  const err = url.searchParams.get("error");
2497
2784
  const errDesc = url.searchParams.get("error_description") ?? void 0;
2498
2785
  if (err) {
@@ -2510,7 +2797,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2510
2797
  res.statusCode = 200;
2511
2798
  res.setHeader("content-type", "text/html; charset=utf-8");
2512
2799
  res.end(SUCCESS_HTML);
2513
- this.resolvePending(code);
2800
+ this.resolvePending({ code, ...iss !== void 0 ? { iss } : {} });
2514
2801
  }
2515
2802
  };
2516
2803
  async function defaultOpener(url) {
@@ -2592,6 +2879,12 @@ var HttpConnector = class extends BaseConnector {
2592
2879
  reconnectionOptions;
2593
2880
  transportType = null;
2594
2881
  streamableTransport = null;
2882
+ /**
2883
+ * Creates an HTTP connector.
2884
+ *
2885
+ * @param baseUrl - MCP endpoint URL.
2886
+ * @param opts - Authentication, transport, SDK, and reconnection options.
2887
+ */
2595
2888
  constructor(baseUrl, opts = {}) {
2596
2889
  super(opts);
2597
2890
  const originalUrl = baseUrl.replace(/\/$/, "");
@@ -2709,7 +3002,12 @@ var HttpConnector = class extends BaseConnector {
2709
3002
  }
2710
3003
  return { fallbackReason, is401Error, httpStatusCode };
2711
3004
  }
2712
- /** Establish connection to the MCP implementation via streamable HTTP. */
3005
+ /**
3006
+ * Establishes a streamable HTTP connection to the MCP server.
3007
+ *
3008
+ * @returns A promise that resolves after protocol negotiation completes.
3009
+ * @throws An error with `code: 401` when authentication is required.
3010
+ */
2713
3011
  async connect() {
2714
3012
  if (this.connected) {
2715
3013
  logger.debug("Already connected to MCP implementation");
@@ -2937,6 +3235,11 @@ var HttpConnector = class extends BaseConnector {
2937
3235
  throw err;
2938
3236
  }
2939
3237
  }
3238
+ /**
3239
+ * Returns fields that identify the endpoint and negotiated transport.
3240
+ *
3241
+ * @returns HTTP connector identity metadata.
3242
+ */
2940
3243
  get publicIdentifier() {
2941
3244
  return {
2942
3245
  type: "http",
@@ -2945,7 +3248,11 @@ var HttpConnector = class extends BaseConnector {
2945
3248
  protocolEra: this.protocolEra ?? "unknown"
2946
3249
  };
2947
3250
  }
2948
- /** Get the active transport type (`streamable-http` once connected). */
3251
+ /**
3252
+ * Returns the active transport type.
3253
+ *
3254
+ * @returns `"streamable-http"` after connection, otherwise `null`.
3255
+ */
2949
3256
  getTransportType() {
2950
3257
  return this.transportType;
2951
3258
  }
@@ -3320,7 +3627,7 @@ var MCPConnection = class {
3320
3627
  /**
3321
3628
  * Normalized server metadata for this ready connection.
3322
3629
  *
3323
- * @throws {Error} When called before protocol negotiation completes.
3630
+ * @throws When called before protocol negotiation completes.
3324
3631
  */
3325
3632
  get info() {
3326
3633
  const protocolEra = this.protocolEra;
@@ -3532,12 +3839,10 @@ function isOAuthClientProvider(provider) {
3532
3839
  var BaseMCPClient = class {
3533
3840
  /**
3534
3841
  * Internal configuration object containing MCP server definitions.
3535
- * @protected
3536
3842
  */
3537
3843
  config = {};
3538
3844
  /**
3539
3845
  * Map of server names to their active sessions.
3540
- * @protected
3541
3846
  */
3542
3847
  sessions = {};
3543
3848
  /**
@@ -3581,7 +3886,7 @@ var BaseMCPClient = class {
3581
3886
  *
3582
3887
  * @param _cfg - Configuration dictionary
3583
3888
  * @returns Client instance
3584
- * @throws {Error} If called on the base class instead of a concrete implementation
3889
+ * @throws If called on the base class instead of a concrete implementation
3585
3890
  *
3586
3891
  * @example
3587
3892
  * ```typescript
@@ -3723,7 +4028,7 @@ var BaseMCPClient = class {
3723
4028
  * @param serverName - The name of the server as defined in the client configuration
3724
4029
  * @param autoInitialize - Whether to automatically initialize the session (default: true)
3725
4030
  * @returns A promise that resolves to the created MCPSession instance
3726
- * @throws {Error} If the server is not found in the configuration
4031
+ * @throws If the server is not found in the configuration
3727
4032
  *
3728
4033
  * @example
3729
4034
  * ```typescript
@@ -3893,7 +4198,7 @@ var BaseMCPClient = class {
3893
4198
  *
3894
4199
  * @param serverName - Name of the server
3895
4200
  * @returns The session instance
3896
- * @throws {Error} If the session is not found
4201
+ * @throws If the session is not found
3897
4202
  *
3898
4203
  * @example
3899
4204
  * ```typescript
@@ -4277,20 +4582,24 @@ global.search_tools = async (query, detailLevel = 'full') => {
4277
4582
  for (const [serverName, serverTools] of Object.entries(tools)) {
4278
4583
  if (!serverTools || serverTools.length === 0) continue;
4279
4584
  const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
4585
+ const escapedServerName = JSON.stringify(serverName);
4586
+ const escapedSafeServerName = JSON.stringify(safeServerName);
4280
4587
  shim += `
4281
- global['${serverName}'] = {`;
4588
+ global[${escapedServerName}] = {`;
4282
4589
  for (const tool of serverTools) {
4590
+ const escapedToolName = JSON.stringify(tool.name);
4283
4591
  shim += `
4284
- '${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
4592
+ [${escapedToolName}]: async (args) => await global.__callMcpTool(${escapedServerName}, ${escapedToolName}, args),`;
4285
4593
  }
4286
4594
  shim += `
4287
4595
  };
4288
-
4596
+ `;
4597
+ if (safeServerName !== serverName) {
4598
+ shim += `
4289
4599
  // Also expose as safe name if different
4290
- if ('${safeServerName}' !== '${serverName}') {
4291
- global['${safeServerName}'] = global['${serverName}'];
4292
- }
4600
+ global[${escapedSafeServerName}] = global[${escapedServerName}];
4293
4601
  `;
4602
+ }
4294
4603
  }
4295
4604
  return shim;
4296
4605
  }
@@ -4984,9 +5293,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
4984
5293
  * @param config - Configuration object or path to JSON config file. If omitted,
4985
5294
  * starts with empty configuration
4986
5295
  * @param options - Optional client behavior configuration
4987
- * @param options.codeMode - Enable code execution mode (boolean or advanced config)
4988
- * @param options.onSampling - Callback for handling sampling requests from servers
4989
- * @param options.onElicitation - Callback for handling elicitation requests
5296
+ * Options can enable code mode or provide sampling and elicitation callbacks.
4990
5297
  *
4991
5298
  * @example
4992
5299
  * ```typescript
@@ -5087,7 +5394,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5087
5394
  * });
5088
5395
  * ```
5089
5396
  *
5090
- * @see {@link constructor} for direct instantiation
5397
+ * @see {@link MCPClient} for direct instantiation
5091
5398
  * @see {@link fromConfigFile} for loading from file
5092
5399
  */
5093
5400
  static fromDict(cfg, options) {
@@ -5102,7 +5409,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5102
5409
  * @param path - Path to the JSON configuration file
5103
5410
  * @param options - Optional client behavior configuration
5104
5411
  * @returns New MCPClient instance
5105
- * @throws {Error} If the file cannot be read or parsed
5412
+ * @throws If the file cannot be read or parsed
5106
5413
  *
5107
5414
  * @example
5108
5415
  * ```typescript
@@ -5118,7 +5425,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5118
5425
  * });
5119
5426
  * ```
5120
5427
  *
5121
- * @see {@link constructor} for direct instantiation
5428
+ * @see {@link MCPClient} for direct instantiation
5122
5429
  * @see {@link fromDict} for inline configuration
5123
5430
  */
5124
5431
  static fromConfigFile(path2, options) {
@@ -5265,7 +5572,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5265
5572
  * @param code - JavaScript/TypeScript code to execute
5266
5573
  * @param timeout - Optional execution timeout in milliseconds
5267
5574
  * @returns Execution result with output, errors, and return value
5268
- * @throws {Error} If code mode is not enabled
5575
+ * @throws If code mode is not enabled
5269
5576
  *
5270
5577
  * @example
5271
5578
  * ```typescript
@@ -5311,7 +5618,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5311
5618
  * @param query - Optional search query to filter tools (defaults to empty string for all tools)
5312
5619
  * @param detailLevel - Level of detail to return: "names", "descriptions", or "full"
5313
5620
  * @returns Tool search results with matching tools
5314
- * @throws {Error} If code mode is not enabled
5621
+ * @throws If code mode is not enabled
5315
5622
  *
5316
5623
  * @example
5317
5624
  * ```typescript