@mcp-use/client 2.0.0-beta.9 → 2.0.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 +407 -92
  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");
@@ -1048,6 +1135,11 @@ var init_stdio = __esm({
1048
1135
  throw err;
1049
1136
  }
1050
1137
  }
1138
+ /**
1139
+ * Returns fields identifying the launched command and arguments.
1140
+ *
1141
+ * @returns Stdio connector identity metadata.
1142
+ */
1051
1143
  get publicIdentifier() {
1052
1144
  return {
1053
1145
  type: "stdio",
@@ -1059,6 +1151,12 @@ var init_stdio = __esm({
1059
1151
  serverParams;
1060
1152
  errlog;
1061
1153
  _transport = null;
1154
+ /**
1155
+ * Creates a connection manager for a local server process.
1156
+ *
1157
+ * @param serverParams - Process parameters passed to the SDK transport.
1158
+ * @param errlog - Destination for the child process's standard error stream.
1159
+ */
1062
1160
  constructor(serverParams, errlog = process2.stderr) {
1063
1161
  super();
1064
1162
  this.serverParams = serverParams;
@@ -1108,7 +1206,7 @@ init_connector_telemetry();
1108
1206
  init_logging();
1109
1207
 
1110
1208
  // src/utils/version.ts
1111
- var VERSION = "2.0.0-beta.8";
1209
+ var VERSION = "2.0.0";
1112
1210
  function getPackageVersion() {
1113
1211
  return VERSION;
1114
1212
  }
@@ -1128,16 +1226,13 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
1128
1226
  return {
1129
1227
  // Core execution info
1130
1228
  execution_method: this.data.executionMethod,
1131
- query: this.data.query,
1132
1229
  query_length: this.data.query.length,
1133
1230
  success: this.data.success,
1134
1231
  // Agent configuration
1135
1232
  model_provider: this.data.modelProvider,
1136
1233
  model_name: this.data.modelName,
1137
1234
  server_count: this.data.serverCount,
1138
- server_identifiers: this.data.serverIdentifiers,
1139
1235
  total_tools_available: this.data.totalToolsAvailable,
1140
- tools_available_names: this.data.toolsAvailableNames,
1141
1236
  max_steps_configured: this.data.maxStepsConfigured,
1142
1237
  memory_enabled: this.data.memoryEnabled,
1143
1238
  use_server_manager: this.data.useServerManager,
@@ -1148,8 +1243,6 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
1148
1243
  // Execution results (always include, even if null)
1149
1244
  steps_taken: this.data.stepsTaken ?? null,
1150
1245
  tools_used_count: this.data.toolsUsedCount ?? null,
1151
- tools_used_names: this.data.toolsUsedNames ?? null,
1152
- response: this.data.response ?? null,
1153
1246
  response_length: this.data.response ? this.data.response.length : null,
1154
1247
  execution_time_ms: this.data.executionTimeMs ?? null,
1155
1248
  error_type: this.data.errorType ?? null,
@@ -1245,21 +1338,72 @@ async function telFetch(url, init) {
1245
1338
  }
1246
1339
  var POSTHOG_HOST = "https://eu.i.posthog.com";
1247
1340
  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({
1341
+ var CONTENT_PROPERTY = /(^|_)(arguments?|args|body|command|headers?|location|message|query|response|secret|subject|token|uri|url|user_agent)(_|$)/i;
1342
+ var IDENTIFYING_PROPERTY = /(^|_)(server_identifiers?|server_names?|servers|tool_names?|tools_(available|used)_names)(_|$)/i;
1343
+ var AGGREGATE_PROPERTY = /(_count|_length|_duration(?:_ms)?|_time_ms|(^|_)num_[a-z0-9_]+)$/i;
1344
+ function normalizePropertyKey(key) {
1345
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_$]+/gi, "_").toLowerCase();
1346
+ }
1347
+ function sanitizeValue(value, seen) {
1348
+ if (Array.isArray(value)) {
1349
+ if (seen.has(value)) {
1350
+ throw new TypeError("Cyclic telemetry properties are not supported");
1351
+ }
1352
+ seen.add(value);
1353
+ const sanitized = value.map((item) => sanitizeValue(item, seen));
1354
+ seen.delete(value);
1355
+ return sanitized;
1356
+ }
1357
+ if (value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) {
1358
+ if (seen.has(value)) {
1359
+ throw new TypeError("Cyclic telemetry properties are not supported");
1360
+ }
1361
+ seen.add(value);
1362
+ const sanitized = sanitizeProperties(
1363
+ value,
1364
+ seen
1365
+ );
1366
+ seen.delete(value);
1367
+ return sanitized;
1368
+ }
1369
+ return value;
1370
+ }
1371
+ function sanitizeProperties(properties, seen = /* @__PURE__ */ new WeakSet()) {
1372
+ const sanitized = {};
1373
+ for (const [key, value] of Object.entries(properties)) {
1374
+ const normalizedKey = normalizePropertyKey(key);
1375
+ if (AGGREGATE_PROPERTY.test(normalizedKey)) {
1376
+ if (value === null || typeof value === "number") {
1377
+ sanitized[key] = value;
1378
+ }
1379
+ continue;
1380
+ }
1381
+ if (IDENTIFYING_PROPERTY.test(normalizedKey) || CONTENT_PROPERTY.test(normalizedKey)) {
1382
+ continue;
1383
+ }
1384
+ sanitized[key] = sanitizeValue(value, seen);
1385
+ }
1386
+ return sanitized;
1387
+ }
1388
+ async function capturePostHog(params) {
1389
+ try {
1390
+ const host = params.host ?? POSTHOG_HOST;
1391
+ const apiKey = params.apiKey ?? POSTHOG_API_KEY;
1392
+ const body = JSON.stringify({
1256
1393
  api_key: apiKey,
1257
1394
  event: params.event,
1258
1395
  distinct_id: params.distinctId,
1259
- properties: params.properties,
1396
+ properties: sanitizeProperties(params.properties),
1260
1397
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1261
- })
1262
- });
1398
+ });
1399
+ await telFetch(`${host}/i/v0/e/`, {
1400
+ method: "POST",
1401
+ headers: { "Content-Type": "application/json" },
1402
+ keepalive: true,
1403
+ body
1404
+ });
1405
+ } catch {
1406
+ }
1263
1407
  }
1264
1408
 
1265
1409
  // src/telemetry/telemetry.ts
@@ -1789,11 +1933,12 @@ async function completeOAuthFlow(provider, serverUrl, options = {}) {
1789
1933
  throw new Error(`Unexpected OAuth auth() result: ${result}`);
1790
1934
  }
1791
1935
  }
1792
- if (typeof flowProvider.getAuthorizationCode === "function") {
1793
- const code = await flowProvider.getAuthorizationCode();
1936
+ if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
1937
+ const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
1794
1938
  await auth(provider, {
1795
1939
  serverUrl,
1796
- authorizationCode: code,
1940
+ authorizationCode: response.code,
1941
+ ...response.iss !== void 0 ? { iss: response.iss } : {},
1797
1942
  fetchFn
1798
1943
  });
1799
1944
  return;
@@ -1807,6 +1952,8 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
1807
1952
  );
1808
1953
  }
1809
1954
  if (provider.useRedirectFlow) {
1955
+ await new Promise(() => {
1956
+ });
1810
1957
  return;
1811
1958
  }
1812
1959
  const tokensKey = provider.getKey?.("tokens");
@@ -1823,25 +1970,29 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
1823
1970
  } catch {
1824
1971
  }
1825
1972
  }
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");
1973
+ try {
1974
+ const result = await runAuthPopup({
1975
+ popup: null,
1976
+ state,
1977
+ tokensKey,
1978
+ timeoutMs
1979
+ });
1980
+ switch (result.kind) {
1981
+ case "success":
1982
+ return;
1983
+ case "cancelled":
1984
+ throw new Error("OAuth authentication was cancelled.");
1985
+ case "timeout":
1986
+ throw new Error(
1987
+ `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
1988
+ );
1989
+ case "error":
1990
+ throw new Error(result.error);
1991
+ default:
1992
+ throw new Error("Unexpected OAuth popup result");
1993
+ }
1994
+ } finally {
1995
+ provider.markFlowComplete?.();
1845
1996
  }
1846
1997
  }
1847
1998
 
@@ -2054,29 +2205,39 @@ var OAuthSessionStore = class _OAuthSessionStore {
2054
2205
  if (ctx) await this.store.set(this.credentialKey("tokens"), serialized);
2055
2206
  await this.store.remove(this.getKey("code_verifier"));
2056
2207
  await this.store.remove(this.getKey("last_auth_url"));
2208
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2057
2209
  }
2058
2210
  async clientInformation(ctx) {
2211
+ if (!this.allowClientSecret) {
2212
+ const registeredRedirectUri = await this.store.get(
2213
+ this.getKey("client_info_redirect_uri")
2214
+ );
2215
+ if (registeredRedirectUri !== this.redirectUrl) {
2216
+ await this.invalidateCredentials("registration");
2217
+ console.info(
2218
+ `[${this.storageKeyPrefix}] Re-registering browser OAuth client after its Inspector callback changed or could not be verified.`
2219
+ );
2220
+ return void 0;
2221
+ }
2222
+ }
2059
2223
  const stored = await this.readCredential("client_info", ctx);
2060
2224
  if (!stored) return void 0;
2061
2225
  const { key, value: clientInfo } = stored;
2062
2226
  try {
2063
2227
  if (!this.allowClientSecret && clientInfo.client_secret) {
2064
- await this.store.remove(key);
2065
- if (ctx) await this.store.remove(this.credentialKey("client_info"));
2228
+ await this.invalidateCredentials("registration");
2066
2229
  console.warn(
2067
- `[${this.storageKeyPrefix}] Removed OAuth client information containing a browser client_secret.`
2230
+ `[${this.storageKeyPrefix}] Recovered stale browser OAuth credentials containing a client_secret.`
2068
2231
  );
2069
2232
  return void 0;
2070
2233
  }
2071
2234
  const storedRedirectUris = Array.isArray(clientInfo.redirect_uris) ? clientInfo.redirect_uris : [];
2072
- const hasMatchingRedirect = storedRedirectUris.length === 0 || storedRedirectUris.includes(this.redirectUrl);
2235
+ const hasMatchingRedirect = storedRedirectUris.length === 0 && this.allowClientSecret || storedRedirectUris.includes(this.redirectUrl);
2073
2236
  if (!hasMatchingRedirect) {
2074
2237
  console.info(
2075
- `[${this.storageKeyPrefix}] Invalidating cached OAuth client info due to redirect URI mismatch.`
2238
+ `[${this.storageKeyPrefix}] Recovering cached OAuth credentials after a redirect URI change.`
2076
2239
  );
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"));
2240
+ await this.invalidateCredentials("registration");
2080
2241
  return void 0;
2081
2242
  }
2082
2243
  return clientInfo;
@@ -2094,11 +2255,20 @@ var OAuthSessionStore = class _OAuthSessionStore {
2094
2255
  "Browser OAuth clients must be public clients; client_secret persistence is not allowed."
2095
2256
  );
2096
2257
  }
2097
- const serialized = JSON.stringify(clientInformation);
2258
+ const persistedClientInformation = !this.allowClientSecret && (!("redirect_uris" in clientInformation) || !Array.isArray(
2259
+ clientInformation.redirect_uris
2260
+ ) || clientInformation.redirect_uris.length === 0) ? { ...clientInformation, redirect_uris: [this.redirectUrl] } : clientInformation;
2261
+ const serialized = JSON.stringify(persistedClientInformation);
2098
2262
  await this.store.set(this.credentialKey("client_info", ctx), serialized);
2099
2263
  if (ctx) {
2100
2264
  await this.store.set(this.credentialKey("client_info"), serialized);
2101
2265
  }
2266
+ if (!this.allowClientSecret) {
2267
+ await this.store.set(
2268
+ this.getKey("client_info_redirect_uri"),
2269
+ this.redirectUrl
2270
+ );
2271
+ }
2102
2272
  }
2103
2273
  async saveCodeVerifier(codeVerifier) {
2104
2274
  await this.store.set(this.getKey("code_verifier"), codeVerifier);
@@ -2123,11 +2293,22 @@ var OAuthSessionStore = class _OAuthSessionStore {
2123
2293
  }
2124
2294
  };
2125
2295
  switch (scope) {
2296
+ case "registration":
2297
+ await removeCredentialKeys("tokens");
2298
+ await removeCredentialKeys("client_info");
2299
+ await this.store.remove(this.getKey("code_verifier"));
2300
+ await this.store.remove(this.getKey("last_auth_url"));
2301
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2302
+ await this.store.remove(this.getKey("client_info_redirect_uri"));
2303
+ await this.store.remove(this.getKey("token_endpoint"));
2304
+ break;
2126
2305
  case "all":
2127
2306
  await removeCredentialKeys("tokens");
2128
2307
  await removeCredentialKeys("client_info");
2129
2308
  await this.store.remove(this.getKey("code_verifier"));
2130
2309
  await this.store.remove(this.getKey("last_auth_url"));
2310
+ await this.store.remove(this.getKey("last_auth_callback_url"));
2311
+ await this.store.remove(this.getKey("client_info_redirect_uri"));
2131
2312
  await this.store.remove(this.getKey("discovery_state"));
2132
2313
  await this.store.remove(this.getKey("token_endpoint"));
2133
2314
  break;
@@ -2177,7 +2358,7 @@ var OAuthSessionStore = class _OAuthSessionStore {
2177
2358
  */
2178
2359
  async storeAuthorizationState(authorizationUrl, opts = {}) {
2179
2360
  const state = globalThis.crypto.randomUUID();
2180
- const stateKey = `${this.storageKeyPrefix}:state_${state}`;
2361
+ const stateKey = `${this.storageKeyPrefix}_${this.serverUrlHash}_state_${state}`;
2181
2362
  const stateData = {
2182
2363
  serverUrlHash: this.serverUrlHash,
2183
2364
  expiry: Date.now() + 1e3 * 60 * 10,
@@ -2197,6 +2378,10 @@ var OAuthSessionStore = class _OAuthSessionStore {
2197
2378
  authorizationUrl.searchParams.set("state", state);
2198
2379
  const sanitizedAuthUrl = sanitizeUrl(authorizationUrl.toString());
2199
2380
  await this.store.set(stateKey, JSON.stringify(stateData));
2381
+ await this.store.set(
2382
+ this.getKey("last_auth_callback_url"),
2383
+ this.redirectUrl
2384
+ );
2200
2385
  await this.store.set(this.getKey("last_auth_url"), sanitizedAuthUrl);
2201
2386
  return sanitizedAuthUrl;
2202
2387
  }
@@ -2222,8 +2407,16 @@ var DEFAULT_PORT = 33418;
2222
2407
  var PORT_RANGE = 10;
2223
2408
  var DEFAULT_AUTH_TIMEOUT_MS2 = 5 * 6e4;
2224
2409
  var OAuthFlowError = class extends Error {
2410
+ /** OAuth or local-flow error code. */
2225
2411
  code;
2412
+ /** Optional human-readable error description. */
2226
2413
  description;
2414
+ /**
2415
+ * Creates an OAuth flow error.
2416
+ *
2417
+ * @param code - OAuth or local-flow error code.
2418
+ * @param description - Optional human-readable description.
2419
+ */
2227
2420
  constructor(code, description) {
2228
2421
  super(description ? `${code}: ${description}` : code);
2229
2422
  this.code = code;
@@ -2273,16 +2466,20 @@ h1{font-size:20px;margin:0 0 12px;color:#b00020}p{line-height:1.5}code{backgroun
2273
2466
  <p><code>${escapeHtml(err)}</code>${desc ? `: ${escapeHtml(desc)}` : ""}</p>
2274
2467
  <p>You can close this tab and return to your terminal.</p></body></html>`;
2275
2468
  var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2469
+ /** Protected MCP server URL associated with this provider. */
2276
2470
  serverUrl;
2471
+ /** Reserved localhost callback port. */
2277
2472
  port;
2278
2473
  session;
2279
2474
  kv;
2280
2475
  authTimeoutMs;
2281
2476
  openBrowserOverride;
2282
2477
  server = null;
2478
+ /** Provider authorization URL, exposed only through the local redirect route. */
2479
+ authorizationUrl = null;
2283
2480
  /** Currently in-flight deferred — used to prevent overlapping flows. */
2284
2481
  pending = null;
2285
- /** Latest deferred (settled or in-flight) what `getAuthorizationCode()` returns. */
2482
+ /** Latest deferred (settled or in-flight) for the loopback response. */
2286
2483
  lastFlow = null;
2287
2484
  pendingTimer = null;
2288
2485
  constructor(serverUrl, port, session, kv, options) {
@@ -2293,6 +2490,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2293
2490
  this.authTimeoutMs = options.authTimeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS2;
2294
2491
  this.openBrowserOverride = options.openBrowser;
2295
2492
  }
2493
+ /**
2494
+ * Creates a Node OAuth provider and reserves a localhost callback port.
2495
+ *
2496
+ * @param serverUrl - Protected MCP server URL.
2497
+ * @param options - OAuth metadata, storage, loopback, and browser options.
2498
+ * @returns A provider ready to participate in the SDK OAuth flow.
2499
+ */
2296
2500
  static async create(serverUrl, options = {}) {
2297
2501
  const serverUrlHash = OAuthSessionStore.hashString(serverUrl);
2298
2502
  const kv = options.kvStore ?? new FileKVStore(serverUrlHash, options.baseDir);
@@ -2325,48 +2529,100 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2325
2529
  return new _NodeOAuthClientProvider(serverUrl, port, session, kv, options);
2326
2530
  }
2327
2531
  // --- Identity passthroughs (parallel to BrowserOAuthClientProvider) ---
2532
+ /** Prefix used for persisted OAuth session keys. */
2328
2533
  get storageKeyPrefix() {
2329
2534
  return this.session.storageKeyPrefix;
2330
2535
  }
2536
+ /** Stable hash of the protected server URL used to namespace storage. */
2331
2537
  get serverUrlHash() {
2332
2538
  return this.session.serverUrlHash;
2333
2539
  }
2334
2540
  // --- SDK Interface (delegated to OAuthSessionStore) ---
2541
+ /** Loopback redirect URL registered for this provider. */
2335
2542
  get redirectUrl() {
2336
2543
  return this.session.redirectUrl;
2337
2544
  }
2545
+ /** OAuth client metadata presented during registration. */
2338
2546
  get clientMetadata() {
2339
2547
  return this.session.clientMetadata;
2340
2548
  }
2549
+ /** OAuth Client ID Metadata Document URL, when configured. */
2341
2550
  get clientMetadataUrl() {
2342
2551
  return this.session.clientMetadataUrl;
2343
2552
  }
2553
+ /**
2554
+ * Loads saved OAuth tokens.
2555
+ *
2556
+ * @param ctx - Optional client registration context.
2557
+ * @returns Saved tokens, or `undefined` when none exist.
2558
+ */
2344
2559
  tokens(ctx) {
2345
2560
  return this.session.tokens(ctx);
2346
2561
  }
2562
+ /**
2563
+ * Persists OAuth tokens.
2564
+ *
2565
+ * @param tokens - Tokens to save.
2566
+ * @param ctx - Optional client registration context.
2567
+ */
2347
2568
  saveTokens(tokens, ctx) {
2348
2569
  return this.session.saveTokens(tokens, ctx);
2349
2570
  }
2571
+ /**
2572
+ * Loads saved OAuth client registration information.
2573
+ *
2574
+ * @param ctx - Optional registration context.
2575
+ * @returns Saved registration information, or `undefined`.
2576
+ */
2350
2577
  clientInformation(ctx) {
2351
2578
  return this.session.clientInformation(ctx);
2352
2579
  }
2580
+ /**
2581
+ * Persists OAuth client registration information.
2582
+ *
2583
+ * @param info - Client information to save.
2584
+ * @param ctx - Optional registration context.
2585
+ */
2353
2586
  saveClientInformation(info, ctx) {
2354
2587
  return this.session.saveClientInformation(info, ctx);
2355
2588
  }
2589
+ /**
2590
+ * Loads the saved PKCE code verifier.
2591
+ *
2592
+ * @returns The saved verifier.
2593
+ */
2356
2594
  codeVerifier() {
2357
2595
  return this.session.codeVerifier();
2358
2596
  }
2597
+ /**
2598
+ * Persists a PKCE code verifier.
2599
+ *
2600
+ * @param codeVerifier - Verifier to save.
2601
+ */
2359
2602
  saveCodeVerifier(codeVerifier) {
2360
2603
  return this.session.saveCodeVerifier(codeVerifier);
2361
2604
  }
2605
+ /**
2606
+ * Invalidates selected persisted OAuth credentials.
2607
+ *
2608
+ * @param scope - Credential group to remove.
2609
+ */
2362
2610
  invalidateCredentials(scope) {
2363
2611
  return this.session.invalidateCredentials(scope);
2364
2612
  }
2365
- /** Persist OAuth discovery state (SEP-2352). Delegated to the session store. */
2613
+ /**
2614
+ * Persists OAuth discovery state.
2615
+ *
2616
+ * @param state - Discovery state to save.
2617
+ */
2366
2618
  saveDiscoveryState(state) {
2367
2619
  return this.session.saveDiscoveryState(state);
2368
2620
  }
2369
- /** Return previously saved OAuth discovery state, or `undefined`. */
2621
+ /**
2622
+ * Returns previously saved OAuth discovery state.
2623
+ *
2624
+ * @returns Saved discovery state, or `undefined`.
2625
+ */
2370
2626
  discoveryState() {
2371
2627
  return this.session.discoveryState();
2372
2628
  }
@@ -2374,6 +2630,10 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2374
2630
  * Bind the loopback server, set up the pending-code deferred, and ask the
2375
2631
  * platform to open the user's browser. Does NOT await the code; the
2376
2632
  * orchestrator awaits via `getAuthorizationCode()`.
2633
+ *
2634
+ * @param authorizationUrl - Authorization URL generated by the SDK.
2635
+ * @returns A promise that resolves once the loopback listener is ready and
2636
+ * the browser-open attempt completes.
2377
2637
  */
2378
2638
  async redirectToAuthorization(authorizationUrl) {
2379
2639
  if (this.pending) {
@@ -2385,6 +2645,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2385
2645
  authorizationUrl,
2386
2646
  { flowType: "redirect" }
2387
2647
  );
2648
+ this.authorizationUrl = sanitizedUrl;
2388
2649
  await this.startLoopback();
2389
2650
  this.pending = createDeferred();
2390
2651
  this.lastFlow = this.pending;
@@ -2399,8 +2660,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2399
2660
  );
2400
2661
  }, this.authTimeoutMs);
2401
2662
  const opener = this.openBrowserOverride ?? defaultOpener;
2663
+ const launcherUrl = `http://127.0.0.1:${this.port}/authorize`;
2402
2664
  try {
2403
- await opener(sanitizedUrl);
2665
+ await opener(launcherUrl);
2404
2666
  } catch (err) {
2405
2667
  console.error(
2406
2668
  `[mcp-use] Could not open browser automatically: ${err instanceof Error ? err.message : String(err)}`
@@ -2409,15 +2671,30 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2409
2671
  }
2410
2672
  /**
2411
2673
  * Resolves with the authorization code captured by the loopback callback.
2674
+ *
2675
+ * @remarks This compatibility method omits the RFC 9207 issuer. OAuth flow
2676
+ * orchestrators should use {@link getAuthorizationResponse} when available.
2412
2677
  * Must be called after `redirectToAuthorization()`. Returns the same
2413
2678
  * promise whether the callback has fired or not — callers may subscribe
2414
2679
  * before or after.
2680
+ *
2681
+ * @returns The authorization code received by the loopback callback.
2415
2682
  */
2416
2683
  getAuthorizationCode() {
2684
+ return this.getAuthorizationResponse().then((response) => response.code);
2685
+ }
2686
+ /**
2687
+ * Resolves with the authorization code and RFC 9207 issuer captured by the
2688
+ * loopback callback.
2689
+ *
2690
+ * @returns The loopback authorization response.
2691
+ * @throws When called before {@link NodeOAuthClientProvider.redirectToAuthorization}.
2692
+ */
2693
+ getAuthorizationResponse() {
2417
2694
  if (!this.lastFlow) {
2418
2695
  return Promise.reject(
2419
2696
  new Error(
2420
- "NodeOAuthClientProvider.getAuthorizationCode() called before redirectToAuthorization()"
2697
+ "NodeOAuthClientProvider.getAuthorizationResponse() called before redirectToAuthorization()"
2421
2698
  )
2422
2699
  );
2423
2700
  }
@@ -2425,6 +2702,9 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2425
2702
  }
2426
2703
  /**
2427
2704
  * Cancel an in-progress flow (timeout, SIGINT, etc.) and close the loopback.
2705
+ *
2706
+ * Pending calls to {@link NodeOAuthClientProvider.getAuthorizationResponse}
2707
+ * reject with an {@link OAuthFlowError} whose code is `"cancelled"`.
2428
2708
  */
2429
2709
  dispose() {
2430
2710
  if (this.pending) {
@@ -2433,7 +2713,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2433
2713
  this.stopLoopback();
2434
2714
  }
2435
2715
  }
2436
- /** Best-effort port for tests / status output. */
2716
+ /** Local callback port, useful for status output and tests. */
2437
2717
  get callbackPort() {
2438
2718
  return this.port;
2439
2719
  }
@@ -2471,12 +2751,13 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2471
2751
  this.server.close();
2472
2752
  this.server = null;
2473
2753
  }
2754
+ this.authorizationUrl = null;
2474
2755
  }
2475
- resolvePending(code) {
2756
+ resolvePending(response) {
2476
2757
  const p = this.pending;
2477
2758
  this.pending = null;
2478
2759
  this.stopLoopback();
2479
- p?.resolve(code);
2760
+ p?.resolve(response);
2480
2761
  }
2481
2762
  rejectPending(err) {
2482
2763
  const p = this.pending;
@@ -2486,6 +2767,19 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2486
2767
  }
2487
2768
  handleCallback(rawUrl, res) {
2488
2769
  const url = new URL(rawUrl, `http://127.0.0.1:${this.port}`);
2770
+ if (url.pathname === "/authorize") {
2771
+ if (this.authorizationUrl === null || this.pending === null) {
2772
+ res.statusCode = 410;
2773
+ res.end("Authorization flow is not active");
2774
+ return;
2775
+ }
2776
+ res.statusCode = 302;
2777
+ res.setHeader("location", this.authorizationUrl);
2778
+ res.setHeader("cache-control", "no-store");
2779
+ res.setHeader("referrer-policy", "no-referrer");
2780
+ res.end();
2781
+ return;
2782
+ }
2489
2783
  if (url.pathname !== "/callback") {
2490
2784
  res.statusCode = 404;
2491
2785
  res.end("Not Found");
@@ -2493,6 +2787,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2493
2787
  }
2494
2788
  const code = url.searchParams.get("code");
2495
2789
  const state = url.searchParams.get("state");
2790
+ const iss = url.searchParams.get("iss") ?? void 0;
2496
2791
  const err = url.searchParams.get("error");
2497
2792
  const errDesc = url.searchParams.get("error_description") ?? void 0;
2498
2793
  if (err) {
@@ -2510,7 +2805,7 @@ var NodeOAuthClientProvider = class _NodeOAuthClientProvider {
2510
2805
  res.statusCode = 200;
2511
2806
  res.setHeader("content-type", "text/html; charset=utf-8");
2512
2807
  res.end(SUCCESS_HTML);
2513
- this.resolvePending(code);
2808
+ this.resolvePending({ code, ...iss !== void 0 ? { iss } : {} });
2514
2809
  }
2515
2810
  };
2516
2811
  async function defaultOpener(url) {
@@ -2592,6 +2887,12 @@ var HttpConnector = class extends BaseConnector {
2592
2887
  reconnectionOptions;
2593
2888
  transportType = null;
2594
2889
  streamableTransport = null;
2890
+ /**
2891
+ * Creates an HTTP connector.
2892
+ *
2893
+ * @param baseUrl - MCP endpoint URL.
2894
+ * @param opts - Authentication, transport, SDK, and reconnection options.
2895
+ */
2595
2896
  constructor(baseUrl, opts = {}) {
2596
2897
  super(opts);
2597
2898
  const originalUrl = baseUrl.replace(/\/$/, "");
@@ -2709,7 +3010,12 @@ var HttpConnector = class extends BaseConnector {
2709
3010
  }
2710
3011
  return { fallbackReason, is401Error, httpStatusCode };
2711
3012
  }
2712
- /** Establish connection to the MCP implementation via streamable HTTP. */
3013
+ /**
3014
+ * Establishes a streamable HTTP connection to the MCP server.
3015
+ *
3016
+ * @returns A promise that resolves after protocol negotiation completes.
3017
+ * @throws An error with `code: 401` when authentication is required.
3018
+ */
2713
3019
  async connect() {
2714
3020
  if (this.connected) {
2715
3021
  logger.debug("Already connected to MCP implementation");
@@ -2937,6 +3243,11 @@ var HttpConnector = class extends BaseConnector {
2937
3243
  throw err;
2938
3244
  }
2939
3245
  }
3246
+ /**
3247
+ * Returns fields that identify the endpoint and negotiated transport.
3248
+ *
3249
+ * @returns HTTP connector identity metadata.
3250
+ */
2940
3251
  get publicIdentifier() {
2941
3252
  return {
2942
3253
  type: "http",
@@ -2945,7 +3256,11 @@ var HttpConnector = class extends BaseConnector {
2945
3256
  protocolEra: this.protocolEra ?? "unknown"
2946
3257
  };
2947
3258
  }
2948
- /** Get the active transport type (`streamable-http` once connected). */
3259
+ /**
3260
+ * Returns the active transport type.
3261
+ *
3262
+ * @returns `"streamable-http"` after connection, otherwise `null`.
3263
+ */
2949
3264
  getTransportType() {
2950
3265
  return this.transportType;
2951
3266
  }
@@ -3320,7 +3635,7 @@ var MCPConnection = class {
3320
3635
  /**
3321
3636
  * Normalized server metadata for this ready connection.
3322
3637
  *
3323
- * @throws {Error} When called before protocol negotiation completes.
3638
+ * @throws When called before protocol negotiation completes.
3324
3639
  */
3325
3640
  get info() {
3326
3641
  const protocolEra = this.protocolEra;
@@ -3532,12 +3847,10 @@ function isOAuthClientProvider(provider) {
3532
3847
  var BaseMCPClient = class {
3533
3848
  /**
3534
3849
  * Internal configuration object containing MCP server definitions.
3535
- * @protected
3536
3850
  */
3537
3851
  config = {};
3538
3852
  /**
3539
3853
  * Map of server names to their active sessions.
3540
- * @protected
3541
3854
  */
3542
3855
  sessions = {};
3543
3856
  /**
@@ -3581,7 +3894,7 @@ var BaseMCPClient = class {
3581
3894
  *
3582
3895
  * @param _cfg - Configuration dictionary
3583
3896
  * @returns Client instance
3584
- * @throws {Error} If called on the base class instead of a concrete implementation
3897
+ * @throws If called on the base class instead of a concrete implementation
3585
3898
  *
3586
3899
  * @example
3587
3900
  * ```typescript
@@ -3723,7 +4036,7 @@ var BaseMCPClient = class {
3723
4036
  * @param serverName - The name of the server as defined in the client configuration
3724
4037
  * @param autoInitialize - Whether to automatically initialize the session (default: true)
3725
4038
  * @returns A promise that resolves to the created MCPSession instance
3726
- * @throws {Error} If the server is not found in the configuration
4039
+ * @throws If the server is not found in the configuration
3727
4040
  *
3728
4041
  * @example
3729
4042
  * ```typescript
@@ -3893,7 +4206,7 @@ var BaseMCPClient = class {
3893
4206
  *
3894
4207
  * @param serverName - Name of the server
3895
4208
  * @returns The session instance
3896
- * @throws {Error} If the session is not found
4209
+ * @throws If the session is not found
3897
4210
  *
3898
4211
  * @example
3899
4212
  * ```typescript
@@ -4277,20 +4590,24 @@ global.search_tools = async (query, detailLevel = 'full') => {
4277
4590
  for (const [serverName, serverTools] of Object.entries(tools)) {
4278
4591
  if (!serverTools || serverTools.length === 0) continue;
4279
4592
  const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
4593
+ const escapedServerName = JSON.stringify(serverName);
4594
+ const escapedSafeServerName = JSON.stringify(safeServerName);
4280
4595
  shim += `
4281
- global['${serverName}'] = {`;
4596
+ global[${escapedServerName}] = {`;
4282
4597
  for (const tool of serverTools) {
4598
+ const escapedToolName = JSON.stringify(tool.name);
4283
4599
  shim += `
4284
- '${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
4600
+ [${escapedToolName}]: async (args) => await global.__callMcpTool(${escapedServerName}, ${escapedToolName}, args),`;
4285
4601
  }
4286
4602
  shim += `
4287
4603
  };
4288
-
4604
+ `;
4605
+ if (safeServerName !== serverName) {
4606
+ shim += `
4289
4607
  // Also expose as safe name if different
4290
- if ('${safeServerName}' !== '${serverName}') {
4291
- global['${safeServerName}'] = global['${serverName}'];
4292
- }
4608
+ global[${escapedSafeServerName}] = global[${escapedServerName}];
4293
4609
  `;
4610
+ }
4294
4611
  }
4295
4612
  return shim;
4296
4613
  }
@@ -4984,9 +5301,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
4984
5301
  * @param config - Configuration object or path to JSON config file. If omitted,
4985
5302
  * starts with empty configuration
4986
5303
  * @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
5304
+ * Options can enable code mode or provide sampling and elicitation callbacks.
4990
5305
  *
4991
5306
  * @example
4992
5307
  * ```typescript
@@ -5087,7 +5402,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5087
5402
  * });
5088
5403
  * ```
5089
5404
  *
5090
- * @see {@link constructor} for direct instantiation
5405
+ * @see {@link MCPClient} for direct instantiation
5091
5406
  * @see {@link fromConfigFile} for loading from file
5092
5407
  */
5093
5408
  static fromDict(cfg, options) {
@@ -5102,7 +5417,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5102
5417
  * @param path - Path to the JSON configuration file
5103
5418
  * @param options - Optional client behavior configuration
5104
5419
  * @returns New MCPClient instance
5105
- * @throws {Error} If the file cannot be read or parsed
5420
+ * @throws If the file cannot be read or parsed
5106
5421
  *
5107
5422
  * @example
5108
5423
  * ```typescript
@@ -5118,7 +5433,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5118
5433
  * });
5119
5434
  * ```
5120
5435
  *
5121
- * @see {@link constructor} for direct instantiation
5436
+ * @see {@link MCPClient} for direct instantiation
5122
5437
  * @see {@link fromDict} for inline configuration
5123
5438
  */
5124
5439
  static fromConfigFile(path2, options) {
@@ -5265,7 +5580,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5265
5580
  * @param code - JavaScript/TypeScript code to execute
5266
5581
  * @param timeout - Optional execution timeout in milliseconds
5267
5582
  * @returns Execution result with output, errors, and return value
5268
- * @throws {Error} If code mode is not enabled
5583
+ * @throws If code mode is not enabled
5269
5584
  *
5270
5585
  * @example
5271
5586
  * ```typescript
@@ -5311,7 +5626,7 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
5311
5626
  * @param query - Optional search query to filter tools (defaults to empty string for all tools)
5312
5627
  * @param detailLevel - Level of detail to return: "names", "descriptions", or "full"
5313
5628
  * @returns Tool search results with matching tools
5314
- * @throws {Error} If code mode is not enabled
5629
+ * @throws If code mode is not enabled
5315
5630
  *
5316
5631
  * @example
5317
5632
  * ```typescript