@atxp/client 0.3.0 → 0.5.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 (40) hide show
  1. package/dist/index.cjs +745 -142
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +745 -142
  4. package/dist/index.js.map +1 -1
  5. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js +369 -99
  6. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js.map +1 -1
  7. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js +18 -18
  8. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js.map +1 -1
  9. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js +162 -0
  10. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js.map +1 -0
  11. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js +86 -14
  12. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js.map +1 -1
  13. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js +47 -9
  14. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js.map +1 -1
  15. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js +64 -5
  16. package/dist/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js.map +1 -1
  17. package/dist/node_modules/eventsource-parser/dist/index.js +1 -1
  18. package/dist/node_modules/eventsource-parser/dist/index.js.map +1 -1
  19. package/dist/node_modules/zod/{dist/esm/v3 → v3}/ZodError.js +3 -2
  20. package/dist/node_modules/zod/v3/ZodError.js.map +1 -0
  21. package/dist/node_modules/zod/v3/errors.js.map +1 -0
  22. package/dist/node_modules/zod/v3/helpers/errorUtil.js.map +1 -0
  23. package/dist/node_modules/zod/v3/helpers/parseUtil.js.map +1 -0
  24. package/dist/node_modules/zod/v3/helpers/util.js.map +1 -0
  25. package/dist/node_modules/zod/{dist/esm/v3 → v3}/locales/en.js +2 -0
  26. package/dist/node_modules/zod/v3/locales/en.js.map +1 -0
  27. package/dist/node_modules/zod/{dist/esm/v3 → v3}/types.js +5 -2
  28. package/dist/node_modules/zod/v3/types.js.map +1 -0
  29. package/package.json +2 -2
  30. package/dist/node_modules/zod/dist/esm/v3/ZodError.js.map +0 -1
  31. package/dist/node_modules/zod/dist/esm/v3/errors.js.map +0 -1
  32. package/dist/node_modules/zod/dist/esm/v3/helpers/errorUtil.js.map +0 -1
  33. package/dist/node_modules/zod/dist/esm/v3/helpers/parseUtil.js.map +0 -1
  34. package/dist/node_modules/zod/dist/esm/v3/helpers/util.js.map +0 -1
  35. package/dist/node_modules/zod/dist/esm/v3/locales/en.js.map +0 -1
  36. package/dist/node_modules/zod/dist/esm/v3/types.js.map +0 -1
  37. /package/dist/node_modules/zod/{dist/esm/v3 → v3}/errors.js +0 -0
  38. /package/dist/node_modules/zod/{dist/esm/v3 → v3}/helpers/errorUtil.js +0 -0
  39. /package/dist/node_modules/zod/{dist/esm/v3 → v3}/helpers/parseUtil.js +0 -0
  40. /package/dist/node_modules/zod/{dist/esm/v3 → v3}/helpers/util.js +0 -0
package/dist/index.cjs CHANGED
@@ -936,8 +936,9 @@ class ZodError extends Error {
936
936
  const formErrors = [];
937
937
  for (const sub of this.issues) {
938
938
  if (sub.path.length > 0) {
939
- fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
940
- fieldErrors[sub.path[0]].push(mapper(sub));
939
+ const firstEl = sub.path[0];
940
+ fieldErrors[firstEl] = fieldErrors[firstEl] || [];
941
+ fieldErrors[firstEl].push(mapper(sub));
941
942
  }
942
943
  else {
943
944
  formErrors.push(mapper(sub));
@@ -1021,6 +1022,8 @@ const errorMap = (issue, _ctx) => {
1021
1022
  message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
1022
1023
  else if (issue.type === "number")
1023
1024
  message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
1025
+ else if (issue.type === "bigint")
1026
+ message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
1024
1027
  else if (issue.type === "date")
1025
1028
  message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
1026
1029
  else
@@ -1618,6 +1621,8 @@ function isValidJWT(jwt, alg) {
1618
1621
  return false;
1619
1622
  try {
1620
1623
  const [header] = jwt.split(".");
1624
+ if (!header)
1625
+ return false;
1621
1626
  // Convert base64url to base64
1622
1627
  const base64 = header
1623
1628
  .replace(/-/g, "+")
@@ -4658,6 +4663,7 @@ const enumType = ZodEnum.create;
4658
4663
  ZodPromise.create;
4659
4664
  const optionalType = ZodOptional.create;
4660
4665
  ZodNullable.create;
4666
+ const NEVER = INVALID;
4661
4667
 
4662
4668
  const LATEST_PROTOCOL_VERSION = "2025-06-18";
4663
4669
  const SUPPORTED_PROTOCOL_VERSIONS = [
@@ -4819,6 +4825,24 @@ const CancelledNotificationSchema = NotificationSchema.extend({
4819
4825
  }),
4820
4826
  });
4821
4827
  /* Base Metadata */
4828
+ /**
4829
+ * Icon schema for use in tools, prompts, resources, and implementations.
4830
+ */
4831
+ const IconSchema = objectType({
4832
+ /**
4833
+ * URL or data URI for the icon.
4834
+ */
4835
+ src: stringType(),
4836
+ /**
4837
+ * Optional MIME type for the icon.
4838
+ */
4839
+ mimeType: optionalType(stringType()),
4840
+ /**
4841
+ * Optional string specifying icon dimensions (e.g., "48x48 96x96").
4842
+ */
4843
+ sizes: optionalType(stringType()),
4844
+ })
4845
+ .passthrough();
4822
4846
  /**
4823
4847
  * Base metadata interface for common properties across resources, tools, prompts, and implementations.
4824
4848
  */
@@ -4842,6 +4866,19 @@ const BaseMetadataSchema = objectType({
4842
4866
  */
4843
4867
  const ImplementationSchema = BaseMetadataSchema.extend({
4844
4868
  version: stringType(),
4869
+ /**
4870
+ * An optional URL of the website for this implementation.
4871
+ */
4872
+ websiteUrl: optionalType(stringType()),
4873
+ /**
4874
+ * An optional list of icons for this implementation.
4875
+ * This can be used by clients to display the implementation in a user interface.
4876
+ * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property.
4877
+ * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml".
4878
+ * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG.
4879
+ * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size.
4880
+ */
4881
+ icons: optionalType(arrayType(IconSchema)),
4845
4882
  });
4846
4883
  /**
4847
4884
  * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.
@@ -5039,11 +5076,27 @@ const TextResourceContentsSchema = ResourceContentsSchema.extend({
5039
5076
  */
5040
5077
  text: stringType(),
5041
5078
  });
5079
+ /**
5080
+ * A Zod schema for validating Base64 strings that is more performant and
5081
+ * robust for very large inputs than the default regex-based check. It avoids
5082
+ * stack overflows by using the native `atob` function for validation.
5083
+ */
5084
+ const Base64Schema = stringType().refine((val) => {
5085
+ try {
5086
+ // atob throws a DOMException if the string contains characters
5087
+ // that are not part of the Base64 character set.
5088
+ atob(val);
5089
+ return true;
5090
+ }
5091
+ catch (_a) {
5092
+ return false;
5093
+ }
5094
+ }, { message: "Invalid Base64 string" });
5042
5095
  const BlobResourceContentsSchema = ResourceContentsSchema.extend({
5043
5096
  /**
5044
5097
  * A base64-encoded string representing the binary data of the item.
5045
5098
  */
5046
- blob: stringType().base64(),
5099
+ blob: Base64Schema,
5047
5100
  });
5048
5101
  /**
5049
5102
  * A known resource that the server is capable of reading.
@@ -5063,6 +5116,10 @@ const ResourceSchema = BaseMetadataSchema.extend({
5063
5116
  * The MIME type of this resource, if known.
5064
5117
  */
5065
5118
  mimeType: optionalType(stringType()),
5119
+ /**
5120
+ * An optional list of icons for this resource.
5121
+ */
5122
+ icons: optionalType(arrayType(IconSchema)),
5066
5123
  /**
5067
5124
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
5068
5125
  * for notes on _meta usage.
@@ -5208,6 +5265,10 @@ const PromptSchema = BaseMetadataSchema.extend({
5208
5265
  * A list of arguments to use for templating the prompt.
5209
5266
  */
5210
5267
  arguments: optionalType(arrayType(PromptArgumentSchema)),
5268
+ /**
5269
+ * An optional list of icons for this prompt.
5270
+ */
5271
+ icons: optionalType(arrayType(IconSchema)),
5211
5272
  /**
5212
5273
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
5213
5274
  * for notes on _meta usage.
@@ -5266,7 +5327,7 @@ const ImageContentSchema = objectType({
5266
5327
  /**
5267
5328
  * The base64-encoded image data.
5268
5329
  */
5269
- data: stringType().base64(),
5330
+ data: Base64Schema,
5270
5331
  /**
5271
5332
  * The MIME type of the image. Different providers may support different image types.
5272
5333
  */
@@ -5286,7 +5347,7 @@ const AudioContentSchema = objectType({
5286
5347
  /**
5287
5348
  * The base64-encoded audio data.
5288
5349
  */
5289
- data: stringType().base64(),
5350
+ data: Base64Schema,
5290
5351
  /**
5291
5352
  * The MIME type of the audio. Different providers may support different audio types.
5292
5353
  */
@@ -5435,6 +5496,10 @@ const ToolSchema = BaseMetadataSchema.extend({
5435
5496
  * Optional additional tool information.
5436
5497
  */
5437
5498
  annotations: optionalType(ToolAnnotationsSchema),
5499
+ /**
5500
+ * An optional list of icons for this tool.
5501
+ */
5502
+ icons: optionalType(arrayType(IconSchema)),
5438
5503
  /**
5439
5504
  * See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
5440
5505
  * for notes on _meta usage.
@@ -5927,6 +5992,7 @@ class Protocol {
5927
5992
  this._responseHandlers = new Map();
5928
5993
  this._progressHandlers = new Map();
5929
5994
  this._timeoutInfo = new Map();
5995
+ this._pendingDebouncedNotifications = new Set();
5930
5996
  this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
5931
5997
  const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
5932
5998
  controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
@@ -6009,6 +6075,7 @@ class Protocol {
6009
6075
  const responseHandlers = this._responseHandlers;
6010
6076
  this._responseHandlers = new Map();
6011
6077
  this._progressHandlers.clear();
6078
+ this._pendingDebouncedNotifications.clear();
6012
6079
  this._transport = undefined;
6013
6080
  (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
6014
6081
  const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
@@ -6033,10 +6100,12 @@ class Protocol {
6033
6100
  .catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
6034
6101
  }
6035
6102
  _onrequest(request, extra) {
6036
- var _a, _b, _c, _d;
6103
+ var _a, _b;
6037
6104
  const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
6105
+ // Capture the current transport at request time to ensure responses go to the correct client
6106
+ const capturedTransport = this._transport;
6038
6107
  if (handler === undefined) {
6039
- (_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
6108
+ capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
6040
6109
  jsonrpc: "2.0",
6041
6110
  id: request.id,
6042
6111
  error: {
@@ -6050,8 +6119,8 @@ class Protocol {
6050
6119
  this._requestHandlerAbortControllers.set(request.id, abortController);
6051
6120
  const fullExtra = {
6052
6121
  signal: abortController.signal,
6053
- sessionId: (_c = this._transport) === null || _c === void 0 ? void 0 : _c.sessionId,
6054
- _meta: (_d = request.params) === null || _d === void 0 ? void 0 : _d._meta,
6122
+ sessionId: capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.sessionId,
6123
+ _meta: (_b = request.params) === null || _b === void 0 ? void 0 : _b._meta,
6055
6124
  sendNotification: (notification) => this.notification(notification, { relatedRequestId: request.id }),
6056
6125
  sendRequest: (r, resultSchema, options) => this.request(r, resultSchema, { ...options, relatedRequestId: request.id }),
6057
6126
  authInfo: extra === null || extra === void 0 ? void 0 : extra.authInfo,
@@ -6062,28 +6131,27 @@ class Protocol {
6062
6131
  Promise.resolve()
6063
6132
  .then(() => handler(request, fullExtra))
6064
6133
  .then((result) => {
6065
- var _a;
6066
6134
  if (abortController.signal.aborted) {
6067
6135
  return;
6068
6136
  }
6069
- return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
6137
+ return capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
6070
6138
  result,
6071
6139
  jsonrpc: "2.0",
6072
6140
  id: request.id,
6073
6141
  });
6074
6142
  }, (error) => {
6075
- var _a, _b;
6143
+ var _a;
6076
6144
  if (abortController.signal.aborted) {
6077
6145
  return;
6078
6146
  }
6079
- return (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send({
6147
+ return capturedTransport === null || capturedTransport === void 0 ? void 0 : capturedTransport.send({
6080
6148
  jsonrpc: "2.0",
6081
6149
  id: request.id,
6082
6150
  error: {
6083
6151
  code: Number.isSafeInteger(error["code"])
6084
6152
  ? error["code"]
6085
6153
  : ErrorCode.InternalError,
6086
- message: (_b = error.message) !== null && _b !== void 0 ? _b : "Internal error",
6154
+ message: (_a = error.message) !== null && _a !== void 0 ? _a : "Internal error",
6087
6155
  },
6088
6156
  });
6089
6157
  })
@@ -6222,10 +6290,45 @@ class Protocol {
6222
6290
  * Emits a notification, which is a one-way message that does not expect a response.
6223
6291
  */
6224
6292
  async notification(notification, options) {
6293
+ var _a, _b;
6225
6294
  if (!this._transport) {
6226
6295
  throw new Error("Not connected");
6227
6296
  }
6228
6297
  this.assertNotificationCapability(notification.method);
6298
+ const debouncedMethods = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.debouncedNotificationMethods) !== null && _b !== void 0 ? _b : [];
6299
+ // A notification can only be debounced if it's in the list AND it's "simple"
6300
+ // (i.e., has no parameters and no related request ID that could be lost).
6301
+ const canDebounce = debouncedMethods.includes(notification.method)
6302
+ && !notification.params
6303
+ && !(options === null || options === void 0 ? void 0 : options.relatedRequestId);
6304
+ if (canDebounce) {
6305
+ // If a notification of this type is already scheduled, do nothing.
6306
+ if (this._pendingDebouncedNotifications.has(notification.method)) {
6307
+ return;
6308
+ }
6309
+ // Mark this notification type as pending.
6310
+ this._pendingDebouncedNotifications.add(notification.method);
6311
+ // Schedule the actual send to happen in the next microtask.
6312
+ // This allows all synchronous calls in the current event loop tick to be coalesced.
6313
+ Promise.resolve().then(() => {
6314
+ var _a;
6315
+ // Un-mark the notification so the next one can be scheduled.
6316
+ this._pendingDebouncedNotifications.delete(notification.method);
6317
+ // SAFETY CHECK: If the connection was closed while this was pending, abort.
6318
+ if (!this._transport) {
6319
+ return;
6320
+ }
6321
+ const jsonrpcNotification = {
6322
+ ...notification,
6323
+ jsonrpc: "2.0",
6324
+ };
6325
+ // Send the notification, but don't await it here to avoid blocking.
6326
+ // Handle potential errors with a .catch().
6327
+ (_a = this._transport) === null || _a === void 0 ? void 0 : _a.send(jsonrpcNotification, options).catch(error => this._onerror(error));
6328
+ });
6329
+ // Return immediately.
6330
+ return;
6331
+ }
6229
6332
  const jsonrpcNotification = {
6230
6333
  ...notification,
6231
6334
  jsonrpc: "2.0",
@@ -14123,12 +14226,29 @@ async function pkceChallenge(length) {
14123
14226
  };
14124
14227
  }
14125
14228
 
14229
+ /**
14230
+ * Reusable URL validation that disallows javascript: scheme
14231
+ */
14232
+ const SafeUrlSchema = stringType().url()
14233
+ .superRefine((val, ctx) => {
14234
+ if (!URL.canParse(val)) {
14235
+ ctx.addIssue({
14236
+ code: ZodIssueCode.custom,
14237
+ message: "URL must be parseable",
14238
+ fatal: true,
14239
+ });
14240
+ return NEVER;
14241
+ }
14242
+ }).refine((url) => {
14243
+ const u = new URL(url);
14244
+ return u.protocol !== 'javascript:' && u.protocol !== 'data:' && u.protocol !== 'vbscript:';
14245
+ }, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
14126
14246
  /**
14127
14247
  * RFC 9728 OAuth Protected Resource Metadata
14128
14248
  */
14129
14249
  const OAuthProtectedResourceMetadataSchema = objectType({
14130
14250
  resource: stringType().url(),
14131
- authorization_servers: arrayType(stringType().url()).optional(),
14251
+ authorization_servers: arrayType(SafeUrlSchema).optional(),
14132
14252
  jwks_uri: stringType().url().optional(),
14133
14253
  scopes_supported: arrayType(stringType()).optional(),
14134
14254
  bearer_methods_supported: arrayType(stringType()).optional(),
@@ -14148,9 +14268,9 @@ const OAuthProtectedResourceMetadataSchema = objectType({
14148
14268
  */
14149
14269
  const OAuthMetadataSchema = objectType({
14150
14270
  issuer: stringType(),
14151
- authorization_endpoint: stringType(),
14152
- token_endpoint: stringType(),
14153
- registration_endpoint: stringType().optional(),
14271
+ authorization_endpoint: SafeUrlSchema,
14272
+ token_endpoint: SafeUrlSchema,
14273
+ registration_endpoint: SafeUrlSchema.optional(),
14154
14274
  scopes_supported: arrayType(stringType()).optional(),
14155
14275
  response_types_supported: arrayType(stringType()),
14156
14276
  response_modes_supported: arrayType(stringType()).optional(),
@@ -14158,8 +14278,8 @@ const OAuthMetadataSchema = objectType({
14158
14278
  token_endpoint_auth_methods_supported: arrayType(stringType()).optional(),
14159
14279
  token_endpoint_auth_signing_alg_values_supported: arrayType(stringType())
14160
14280
  .optional(),
14161
- service_documentation: stringType().optional(),
14162
- revocation_endpoint: stringType().optional(),
14281
+ service_documentation: SafeUrlSchema.optional(),
14282
+ revocation_endpoint: SafeUrlSchema.optional(),
14163
14283
  revocation_endpoint_auth_methods_supported: arrayType(stringType()).optional(),
14164
14284
  revocation_endpoint_auth_signing_alg_values_supported: arrayType(stringType())
14165
14285
  .optional(),
@@ -14171,11 +14291,65 @@ const OAuthMetadataSchema = objectType({
14171
14291
  code_challenge_methods_supported: arrayType(stringType()).optional(),
14172
14292
  })
14173
14293
  .passthrough();
14294
+ /**
14295
+ * OpenID Connect Discovery 1.0 Provider Metadata
14296
+ * see: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
14297
+ */
14298
+ const OpenIdProviderMetadataSchema = objectType({
14299
+ issuer: stringType(),
14300
+ authorization_endpoint: SafeUrlSchema,
14301
+ token_endpoint: SafeUrlSchema,
14302
+ userinfo_endpoint: SafeUrlSchema.optional(),
14303
+ jwks_uri: SafeUrlSchema,
14304
+ registration_endpoint: SafeUrlSchema.optional(),
14305
+ scopes_supported: arrayType(stringType()).optional(),
14306
+ response_types_supported: arrayType(stringType()),
14307
+ response_modes_supported: arrayType(stringType()).optional(),
14308
+ grant_types_supported: arrayType(stringType()).optional(),
14309
+ acr_values_supported: arrayType(stringType()).optional(),
14310
+ subject_types_supported: arrayType(stringType()),
14311
+ id_token_signing_alg_values_supported: arrayType(stringType()),
14312
+ id_token_encryption_alg_values_supported: arrayType(stringType()).optional(),
14313
+ id_token_encryption_enc_values_supported: arrayType(stringType()).optional(),
14314
+ userinfo_signing_alg_values_supported: arrayType(stringType()).optional(),
14315
+ userinfo_encryption_alg_values_supported: arrayType(stringType()).optional(),
14316
+ userinfo_encryption_enc_values_supported: arrayType(stringType()).optional(),
14317
+ request_object_signing_alg_values_supported: arrayType(stringType()).optional(),
14318
+ request_object_encryption_alg_values_supported: arrayType(stringType())
14319
+ .optional(),
14320
+ request_object_encryption_enc_values_supported: arrayType(stringType())
14321
+ .optional(),
14322
+ token_endpoint_auth_methods_supported: arrayType(stringType()).optional(),
14323
+ token_endpoint_auth_signing_alg_values_supported: arrayType(stringType())
14324
+ .optional(),
14325
+ display_values_supported: arrayType(stringType()).optional(),
14326
+ claim_types_supported: arrayType(stringType()).optional(),
14327
+ claims_supported: arrayType(stringType()).optional(),
14328
+ service_documentation: stringType().optional(),
14329
+ claims_locales_supported: arrayType(stringType()).optional(),
14330
+ ui_locales_supported: arrayType(stringType()).optional(),
14331
+ claims_parameter_supported: booleanType().optional(),
14332
+ request_parameter_supported: booleanType().optional(),
14333
+ request_uri_parameter_supported: booleanType().optional(),
14334
+ require_request_uri_registration: booleanType().optional(),
14335
+ op_policy_uri: SafeUrlSchema.optional(),
14336
+ op_tos_uri: SafeUrlSchema.optional(),
14337
+ })
14338
+ .passthrough();
14339
+ /**
14340
+ * OpenID Connect Discovery metadata that may include OAuth 2.0 fields
14341
+ * This schema represents the real-world scenario where OIDC providers
14342
+ * return a mix of OpenID Connect and OAuth 2.0 metadata fields
14343
+ */
14344
+ const OpenIdProviderDiscoveryMetadataSchema = OpenIdProviderMetadataSchema.merge(OAuthMetadataSchema.pick({
14345
+ code_challenge_methods_supported: true,
14346
+ }));
14174
14347
  /**
14175
14348
  * OAuth 2.1 token response
14176
14349
  */
14177
14350
  const OAuthTokensSchema = objectType({
14178
14351
  access_token: stringType(),
14352
+ id_token: stringType().optional(), // Optional for OAuth 2.1, but necessary in OpenID Connect
14179
14353
  token_type: stringType(),
14180
14354
  expires_in: numberType().optional(),
14181
14355
  scope: stringType().optional(),
@@ -14185,7 +14359,7 @@ const OAuthTokensSchema = objectType({
14185
14359
  /**
14186
14360
  * OAuth 2.1 error response
14187
14361
  */
14188
- objectType({
14362
+ const OAuthErrorResponseSchema = objectType({
14189
14363
  error: stringType(),
14190
14364
  error_description: stringType().optional(),
14191
14365
  error_uri: stringType().optional(),
@@ -14194,18 +14368,18 @@ objectType({
14194
14368
  * RFC 7591 OAuth 2.0 Dynamic Client Registration metadata
14195
14369
  */
14196
14370
  const OAuthClientMetadataSchema = objectType({
14197
- redirect_uris: arrayType(stringType()).refine((uris) => uris.every((uri) => URL.canParse(uri)), { message: "redirect_uris must contain valid URLs" }),
14371
+ redirect_uris: arrayType(SafeUrlSchema),
14198
14372
  token_endpoint_auth_method: stringType().optional(),
14199
14373
  grant_types: arrayType(stringType()).optional(),
14200
14374
  response_types: arrayType(stringType()).optional(),
14201
14375
  client_name: stringType().optional(),
14202
- client_uri: stringType().optional(),
14203
- logo_uri: stringType().optional(),
14376
+ client_uri: SafeUrlSchema.optional(),
14377
+ logo_uri: SafeUrlSchema.optional(),
14204
14378
  scope: stringType().optional(),
14205
14379
  contacts: arrayType(stringType()).optional(),
14206
- tos_uri: stringType().optional(),
14380
+ tos_uri: SafeUrlSchema.optional(),
14207
14381
  policy_uri: stringType().optional(),
14208
- jwks_uri: stringType().optional(),
14382
+ jwks_uri: SafeUrlSchema.optional(),
14209
14383
  jwks: anyType().optional(),
14210
14384
  software_id: stringType().optional(),
14211
14385
  software_version: stringType().optional(),
@@ -14283,22 +14457,313 @@ function checkResourceAllowed({ requestedResource, configuredResource }) {
14283
14457
  return requestedPath.startsWith(configuredPath);
14284
14458
  }
14285
14459
 
14460
+ /**
14461
+ * Base class for all OAuth errors
14462
+ */
14463
+ class OAuthError extends Error {
14464
+ constructor(message, errorUri) {
14465
+ super(message);
14466
+ this.errorUri = errorUri;
14467
+ this.name = this.constructor.name;
14468
+ }
14469
+ /**
14470
+ * Converts the error to a standard OAuth error response object
14471
+ */
14472
+ toResponseObject() {
14473
+ const response = {
14474
+ error: this.errorCode,
14475
+ error_description: this.message
14476
+ };
14477
+ if (this.errorUri) {
14478
+ response.error_uri = this.errorUri;
14479
+ }
14480
+ return response;
14481
+ }
14482
+ get errorCode() {
14483
+ return this.constructor.errorCode;
14484
+ }
14485
+ }
14486
+ /**
14487
+ * Invalid request error - The request is missing a required parameter,
14488
+ * includes an invalid parameter value, includes a parameter more than once,
14489
+ * or is otherwise malformed.
14490
+ */
14491
+ class InvalidRequestError extends OAuthError {
14492
+ }
14493
+ InvalidRequestError.errorCode = "invalid_request";
14494
+ /**
14495
+ * Invalid client error - Client authentication failed (e.g., unknown client, no client
14496
+ * authentication included, or unsupported authentication method).
14497
+ */
14498
+ class InvalidClientError extends OAuthError {
14499
+ }
14500
+ InvalidClientError.errorCode = "invalid_client";
14501
+ /**
14502
+ * Invalid grant error - The provided authorization grant or refresh token is
14503
+ * invalid, expired, revoked, does not match the redirection URI used in the
14504
+ * authorization request, or was issued to another client.
14505
+ */
14506
+ class InvalidGrantError extends OAuthError {
14507
+ }
14508
+ InvalidGrantError.errorCode = "invalid_grant";
14509
+ /**
14510
+ * Unauthorized client error - The authenticated client is not authorized to use
14511
+ * this authorization grant type.
14512
+ */
14513
+ class UnauthorizedClientError extends OAuthError {
14514
+ }
14515
+ UnauthorizedClientError.errorCode = "unauthorized_client";
14516
+ /**
14517
+ * Unsupported grant type error - The authorization grant type is not supported
14518
+ * by the authorization server.
14519
+ */
14520
+ class UnsupportedGrantTypeError extends OAuthError {
14521
+ }
14522
+ UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
14523
+ /**
14524
+ * Invalid scope error - The requested scope is invalid, unknown, malformed, or
14525
+ * exceeds the scope granted by the resource owner.
14526
+ */
14527
+ class InvalidScopeError extends OAuthError {
14528
+ }
14529
+ InvalidScopeError.errorCode = "invalid_scope";
14530
+ /**
14531
+ * Access denied error - The resource owner or authorization server denied the request.
14532
+ */
14533
+ class AccessDeniedError extends OAuthError {
14534
+ }
14535
+ AccessDeniedError.errorCode = "access_denied";
14536
+ /**
14537
+ * Server error - The authorization server encountered an unexpected condition
14538
+ * that prevented it from fulfilling the request.
14539
+ */
14540
+ class ServerError extends OAuthError {
14541
+ }
14542
+ ServerError.errorCode = "server_error";
14543
+ /**
14544
+ * Temporarily unavailable error - The authorization server is currently unable to
14545
+ * handle the request due to a temporary overloading or maintenance of the server.
14546
+ */
14547
+ class TemporarilyUnavailableError extends OAuthError {
14548
+ }
14549
+ TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
14550
+ /**
14551
+ * Unsupported response type error - The authorization server does not support
14552
+ * obtaining an authorization code using this method.
14553
+ */
14554
+ class UnsupportedResponseTypeError extends OAuthError {
14555
+ }
14556
+ UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
14557
+ /**
14558
+ * Unsupported token type error - The authorization server does not support
14559
+ * the requested token type.
14560
+ */
14561
+ class UnsupportedTokenTypeError extends OAuthError {
14562
+ }
14563
+ UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
14564
+ /**
14565
+ * Invalid token error - The access token provided is expired, revoked, malformed,
14566
+ * or invalid for other reasons.
14567
+ */
14568
+ class InvalidTokenError extends OAuthError {
14569
+ }
14570
+ InvalidTokenError.errorCode = "invalid_token";
14571
+ /**
14572
+ * Method not allowed error - The HTTP method used is not allowed for this endpoint.
14573
+ * (Custom, non-standard error)
14574
+ */
14575
+ class MethodNotAllowedError extends OAuthError {
14576
+ }
14577
+ MethodNotAllowedError.errorCode = "method_not_allowed";
14578
+ /**
14579
+ * Too many requests error - Rate limit exceeded.
14580
+ * (Custom, non-standard error based on RFC 6585)
14581
+ */
14582
+ class TooManyRequestsError extends OAuthError {
14583
+ }
14584
+ TooManyRequestsError.errorCode = "too_many_requests";
14585
+ /**
14586
+ * Invalid client metadata error - The client metadata is invalid.
14587
+ * (Custom error for dynamic client registration - RFC 7591)
14588
+ */
14589
+ class InvalidClientMetadataError extends OAuthError {
14590
+ }
14591
+ InvalidClientMetadataError.errorCode = "invalid_client_metadata";
14592
+ /**
14593
+ * Insufficient scope error - The request requires higher privileges than provided by the access token.
14594
+ */
14595
+ class InsufficientScopeError extends OAuthError {
14596
+ }
14597
+ InsufficientScopeError.errorCode = "insufficient_scope";
14598
+ /**
14599
+ * A full list of all OAuthErrors, enabling parsing from error responses
14600
+ */
14601
+ const OAUTH_ERRORS = {
14602
+ [InvalidRequestError.errorCode]: InvalidRequestError,
14603
+ [InvalidClientError.errorCode]: InvalidClientError,
14604
+ [InvalidGrantError.errorCode]: InvalidGrantError,
14605
+ [UnauthorizedClientError.errorCode]: UnauthorizedClientError,
14606
+ [UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
14607
+ [InvalidScopeError.errorCode]: InvalidScopeError,
14608
+ [AccessDeniedError.errorCode]: AccessDeniedError,
14609
+ [ServerError.errorCode]: ServerError,
14610
+ [TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
14611
+ [UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
14612
+ [UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
14613
+ [InvalidTokenError.errorCode]: InvalidTokenError,
14614
+ [MethodNotAllowedError.errorCode]: MethodNotAllowedError,
14615
+ [TooManyRequestsError.errorCode]: TooManyRequestsError,
14616
+ [InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
14617
+ [InsufficientScopeError.errorCode]: InsufficientScopeError,
14618
+ };
14619
+
14286
14620
  class UnauthorizedError extends Error {
14287
14621
  constructor(message) {
14288
14622
  super(message !== null && message !== void 0 ? message : "Unauthorized");
14289
14623
  }
14290
14624
  }
14625
+ /**
14626
+ * Determines the best client authentication method to use based on server support and client configuration.
14627
+ *
14628
+ * Priority order (highest to lowest):
14629
+ * 1. client_secret_basic (if client secret is available)
14630
+ * 2. client_secret_post (if client secret is available)
14631
+ * 3. none (for public clients)
14632
+ *
14633
+ * @param clientInformation - OAuth client information containing credentials
14634
+ * @param supportedMethods - Authentication methods supported by the authorization server
14635
+ * @returns The selected authentication method
14636
+ */
14637
+ function selectClientAuthMethod(clientInformation, supportedMethods) {
14638
+ const hasClientSecret = clientInformation.client_secret !== undefined;
14639
+ // If server doesn't specify supported methods, use RFC 6749 defaults
14640
+ if (supportedMethods.length === 0) {
14641
+ return hasClientSecret ? "client_secret_post" : "none";
14642
+ }
14643
+ // Try methods in priority order (most secure first)
14644
+ if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
14645
+ return "client_secret_basic";
14646
+ }
14647
+ if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
14648
+ return "client_secret_post";
14649
+ }
14650
+ if (supportedMethods.includes("none")) {
14651
+ return "none";
14652
+ }
14653
+ // Fallback: use what we have
14654
+ return hasClientSecret ? "client_secret_post" : "none";
14655
+ }
14656
+ /**
14657
+ * Applies client authentication to the request based on the specified method.
14658
+ *
14659
+ * Implements OAuth 2.1 client authentication methods:
14660
+ * - client_secret_basic: HTTP Basic authentication (RFC 6749 Section 2.3.1)
14661
+ * - client_secret_post: Credentials in request body (RFC 6749 Section 2.3.1)
14662
+ * - none: Public client authentication (RFC 6749 Section 2.1)
14663
+ *
14664
+ * @param method - The authentication method to use
14665
+ * @param clientInformation - OAuth client information containing credentials
14666
+ * @param headers - HTTP headers object to modify
14667
+ * @param params - URL search parameters to modify
14668
+ * @throws {Error} When required credentials are missing
14669
+ */
14670
+ function applyClientAuthentication(method, clientInformation, headers, params) {
14671
+ const { client_id, client_secret } = clientInformation;
14672
+ switch (method) {
14673
+ case "client_secret_basic":
14674
+ applyBasicAuth(client_id, client_secret, headers);
14675
+ return;
14676
+ case "client_secret_post":
14677
+ applyPostAuth(client_id, client_secret, params);
14678
+ return;
14679
+ case "none":
14680
+ applyPublicAuth(client_id, params);
14681
+ return;
14682
+ default:
14683
+ throw new Error(`Unsupported client authentication method: ${method}`);
14684
+ }
14685
+ }
14686
+ /**
14687
+ * Applies HTTP Basic authentication (RFC 6749 Section 2.3.1)
14688
+ */
14689
+ function applyBasicAuth(clientId, clientSecret, headers) {
14690
+ if (!clientSecret) {
14691
+ throw new Error("client_secret_basic authentication requires a client_secret");
14692
+ }
14693
+ const credentials = btoa(`${clientId}:${clientSecret}`);
14694
+ headers.set("Authorization", `Basic ${credentials}`);
14695
+ }
14696
+ /**
14697
+ * Applies POST body authentication (RFC 6749 Section 2.3.1)
14698
+ */
14699
+ function applyPostAuth(clientId, clientSecret, params) {
14700
+ params.set("client_id", clientId);
14701
+ if (clientSecret) {
14702
+ params.set("client_secret", clientSecret);
14703
+ }
14704
+ }
14705
+ /**
14706
+ * Applies public client authentication (RFC 6749 Section 2.1)
14707
+ */
14708
+ function applyPublicAuth(clientId, params) {
14709
+ params.set("client_id", clientId);
14710
+ }
14711
+ /**
14712
+ * Parses an OAuth error response from a string or Response object.
14713
+ *
14714
+ * If the input is a standard OAuth2.0 error response, it will be parsed according to the spec
14715
+ * and an instance of the appropriate OAuthError subclass will be returned.
14716
+ * If parsing fails, it falls back to a generic ServerError that includes
14717
+ * the response status (if available) and original content.
14718
+ *
14719
+ * @param input - A Response object or string containing the error response
14720
+ * @returns A Promise that resolves to an OAuthError instance
14721
+ */
14722
+ async function parseErrorResponse(input) {
14723
+ const statusCode = input instanceof Response ? input.status : undefined;
14724
+ const body = input instanceof Response ? await input.text() : input;
14725
+ try {
14726
+ const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
14727
+ const { error, error_description, error_uri } = result;
14728
+ const errorClass = OAUTH_ERRORS[error] || ServerError;
14729
+ return new errorClass(error_description || '', error_uri);
14730
+ }
14731
+ catch (error) {
14732
+ // Not a valid OAuth error response, but try to inform the user of the raw data anyway
14733
+ const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ''}Invalid OAuth error response: ${error}. Raw body: ${body}`;
14734
+ return new ServerError(errorMessage);
14735
+ }
14736
+ }
14291
14737
  /**
14292
14738
  * Orchestrates the full auth flow with a server.
14293
14739
  *
14294
14740
  * This can be used as a single entry point for all authorization functionality,
14295
14741
  * instead of linking together the other lower-level functions in this module.
14296
14742
  */
14297
- async function auth(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl }) {
14743
+ async function auth(provider, options) {
14744
+ var _a, _b;
14745
+ try {
14746
+ return await authInternal(provider, options);
14747
+ }
14748
+ catch (error) {
14749
+ // Handle recoverable error types by invalidating credentials and retrying
14750
+ if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
14751
+ await ((_a = provider.invalidateCredentials) === null || _a === void 0 ? void 0 : _a.call(provider, 'all'));
14752
+ return await authInternal(provider, options);
14753
+ }
14754
+ else if (error instanceof InvalidGrantError) {
14755
+ await ((_b = provider.invalidateCredentials) === null || _b === void 0 ? void 0 : _b.call(provider, 'tokens'));
14756
+ return await authInternal(provider, options);
14757
+ }
14758
+ // Throw otherwise
14759
+ throw error;
14760
+ }
14761
+ }
14762
+ async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn, }) {
14298
14763
  let resourceMetadata;
14299
- let authorizationServerUrl = serverUrl;
14764
+ let authorizationServerUrl;
14300
14765
  try {
14301
- resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl });
14766
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl }, fetchFn);
14302
14767
  if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
14303
14768
  authorizationServerUrl = resourceMetadata.authorization_servers[0];
14304
14769
  }
@@ -14306,8 +14771,17 @@ async function auth(provider, { serverUrl, authorizationCode, scope, resourceMet
14306
14771
  catch (_a) {
14307
14772
  // Ignore errors and fall back to /.well-known/oauth-authorization-server
14308
14773
  }
14774
+ /**
14775
+ * If we don't get a valid authorization server metadata from protected resource metadata,
14776
+ * fallback to the legacy MCP spec's implementation (version 2025-03-26): MCP server acts as the Authorization server.
14777
+ */
14778
+ if (!authorizationServerUrl) {
14779
+ authorizationServerUrl = serverUrl;
14780
+ }
14309
14781
  const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
14310
- const metadata = await discoverOAuthMetadata(authorizationServerUrl);
14782
+ const metadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, {
14783
+ fetchFn,
14784
+ });
14311
14785
  // Handle client registration if needed
14312
14786
  let clientInformation = await Promise.resolve(provider.clientInformation());
14313
14787
  if (!clientInformation) {
@@ -14320,6 +14794,7 @@ async function auth(provider, { serverUrl, authorizationCode, scope, resourceMet
14320
14794
  const fullInformation = await registerClient(authorizationServerUrl, {
14321
14795
  metadata,
14322
14796
  clientMetadata: provider.clientMetadata,
14797
+ fetchFn,
14323
14798
  });
14324
14799
  await provider.saveClientInformation(fullInformation);
14325
14800
  clientInformation = fullInformation;
@@ -14334,6 +14809,8 @@ async function auth(provider, { serverUrl, authorizationCode, scope, resourceMet
14334
14809
  codeVerifier,
14335
14810
  redirectUri: provider.redirectUrl,
14336
14811
  resource,
14812
+ addClientAuthentication: provider.addClientAuthentication,
14813
+ fetchFn: fetchFn,
14337
14814
  });
14338
14815
  await provider.saveTokens(tokens);
14339
14816
  return "AUTHORIZED";
@@ -14348,12 +14825,19 @@ async function auth(provider, { serverUrl, authorizationCode, scope, resourceMet
14348
14825
  clientInformation,
14349
14826
  refreshToken: tokens.refresh_token,
14350
14827
  resource,
14828
+ addClientAuthentication: provider.addClientAuthentication,
14829
+ fetchFn,
14351
14830
  });
14352
14831
  await provider.saveTokens(newTokens);
14353
14832
  return "AUTHORIZED";
14354
14833
  }
14355
- catch (_b) {
14356
- // Could not refresh OAuth tokens
14834
+ catch (error) {
14835
+ // If this is a ServerError, or an unknown type, log it out and try to continue. Otherwise, escalate so we can fix things and retry.
14836
+ if (!(error instanceof OAuthError) || error instanceof ServerError) ;
14837
+ else {
14838
+ // Refresh failed for another reason, re-throw
14839
+ throw error;
14840
+ }
14357
14841
  }
14358
14842
  }
14359
14843
  const state = provider.state ? await provider.state() : undefined;
@@ -14417,33 +14901,12 @@ function extractResourceMetadataUrl(res) {
14417
14901
  * If the server returns a 404 for the well-known endpoint, this function will
14418
14902
  * return `undefined`. Any other errors will be thrown as exceptions.
14419
14903
  */
14420
- async function discoverOAuthProtectedResourceMetadata(serverUrl, opts) {
14421
- var _a;
14422
- let url;
14423
- if (opts === null || opts === void 0 ? void 0 : opts.resourceMetadataUrl) {
14424
- url = new URL(opts === null || opts === void 0 ? void 0 : opts.resourceMetadataUrl);
14425
- }
14426
- else {
14427
- url = new URL("/.well-known/oauth-protected-resource", serverUrl);
14428
- }
14429
- let response;
14430
- try {
14431
- response = await fetch(url, {
14432
- headers: {
14433
- "MCP-Protocol-Version": (_a = opts === null || opts === void 0 ? void 0 : opts.protocolVersion) !== null && _a !== void 0 ? _a : LATEST_PROTOCOL_VERSION
14434
- }
14435
- });
14436
- }
14437
- catch (error) {
14438
- // CORS errors come back as TypeError
14439
- if (error instanceof TypeError) {
14440
- response = await fetch(url);
14441
- }
14442
- else {
14443
- throw error;
14444
- }
14445
- }
14446
- if (response.status === 404) {
14904
+ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
14905
+ const response = await discoverMetadataWithFallback(serverUrl, 'oauth-protected-resource', fetchFn, {
14906
+ protocolVersion: opts === null || opts === void 0 ? void 0 : opts.protocolVersion,
14907
+ metadataUrl: opts === null || opts === void 0 ? void 0 : opts.resourceMetadataUrl,
14908
+ });
14909
+ if (!response || response.status === 404) {
14447
14910
  throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
14448
14911
  }
14449
14912
  if (!response.ok) {
@@ -14454,15 +14917,15 @@ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts) {
14454
14917
  /**
14455
14918
  * Helper function to handle fetch with CORS retry logic
14456
14919
  */
14457
- async function fetchWithCorsRetry(url, headers) {
14920
+ async function fetchWithCorsRetry(url, headers, fetchFn = fetch) {
14458
14921
  try {
14459
- return await fetch(url, { headers });
14922
+ return await fetchFn(url, { headers });
14460
14923
  }
14461
14924
  catch (error) {
14462
14925
  if (error instanceof TypeError) {
14463
14926
  if (headers) {
14464
14927
  // CORS errors come back as TypeError, retry without headers
14465
- return fetchWithCorsRetry(url);
14928
+ return fetchWithCorsRetry(url, undefined, fetchFn);
14466
14929
  }
14467
14930
  else {
14468
14931
  // We're getting CORS errors on retry too, return undefined
@@ -14473,57 +14936,162 @@ async function fetchWithCorsRetry(url, headers) {
14473
14936
  }
14474
14937
  }
14475
14938
  /**
14476
- * Constructs the well-known path for OAuth metadata discovery
14939
+ * Constructs the well-known path for auth-related metadata discovery
14477
14940
  */
14478
- function buildWellKnownPath(pathname) {
14479
- let wellKnownPath = `/.well-known/oauth-authorization-server${pathname}`;
14941
+ function buildWellKnownPath(wellKnownPrefix, pathname = '', options = {}) {
14942
+ // Strip trailing slash from pathname to avoid double slashes
14480
14943
  if (pathname.endsWith('/')) {
14481
- // Strip trailing slash from pathname to avoid double slashes
14482
- wellKnownPath = wellKnownPath.slice(0, -1);
14944
+ pathname = pathname.slice(0, -1);
14483
14945
  }
14484
- return wellKnownPath;
14946
+ return options.prependPathname
14947
+ ? `${pathname}/.well-known/${wellKnownPrefix}`
14948
+ : `/.well-known/${wellKnownPrefix}${pathname}`;
14485
14949
  }
14486
14950
  /**
14487
14951
  * Tries to discover OAuth metadata at a specific URL
14488
14952
  */
14489
- async function tryMetadataDiscovery(url, protocolVersion) {
14953
+ async function tryMetadataDiscovery(url, protocolVersion, fetchFn = fetch) {
14490
14954
  const headers = {
14491
14955
  "MCP-Protocol-Version": protocolVersion
14492
14956
  };
14493
- return await fetchWithCorsRetry(url, headers);
14957
+ return await fetchWithCorsRetry(url, headers, fetchFn);
14494
14958
  }
14495
14959
  /**
14496
14960
  * Determines if fallback to root discovery should be attempted
14497
14961
  */
14498
14962
  function shouldAttemptFallback(response, pathname) {
14499
- return !response || response.status === 404 && pathname !== '/';
14963
+ return !response || (response.status >= 400 && response.status < 500) && pathname !== '/';
14500
14964
  }
14501
14965
  /**
14502
- * Looks up RFC 8414 OAuth 2.0 Authorization Server Metadata.
14503
- *
14504
- * If the server returns a 404 for the well-known endpoint, this function will
14505
- * return `undefined`. Any other errors will be thrown as exceptions.
14966
+ * Generic function for discovering OAuth metadata with fallback support
14506
14967
  */
14507
- async function discoverOAuthMetadata(authorizationServerUrl, opts) {
14508
- var _a;
14509
- const issuer = new URL(authorizationServerUrl);
14510
- const protocolVersion = (_a = void 0 ) !== null && _a !== void 0 ? _a : LATEST_PROTOCOL_VERSION;
14511
- // Try path-aware discovery first (RFC 8414 compliant)
14512
- const wellKnownPath = buildWellKnownPath(issuer.pathname);
14513
- const pathAwareUrl = new URL(wellKnownPath, issuer);
14514
- let response = await tryMetadataDiscovery(pathAwareUrl, protocolVersion);
14515
- // If path-aware discovery fails with 404, try fallback to root discovery
14516
- if (shouldAttemptFallback(response, issuer.pathname)) {
14517
- const rootUrl = new URL("/.well-known/oauth-authorization-server", issuer);
14518
- response = await tryMetadataDiscovery(rootUrl, protocolVersion);
14968
+ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
14969
+ var _a, _b;
14970
+ const issuer = new URL(serverUrl);
14971
+ const protocolVersion = (_a = opts === null || opts === void 0 ? void 0 : opts.protocolVersion) !== null && _a !== void 0 ? _a : LATEST_PROTOCOL_VERSION;
14972
+ let url;
14973
+ if (opts === null || opts === void 0 ? void 0 : opts.metadataUrl) {
14974
+ url = new URL(opts.metadataUrl);
14519
14975
  }
14520
- if (!response || response.status === 404) {
14521
- return undefined;
14976
+ else {
14977
+ // Try path-aware discovery first
14978
+ const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
14979
+ url = new URL(wellKnownPath, (_b = opts === null || opts === void 0 ? void 0 : opts.metadataServerUrl) !== null && _b !== void 0 ? _b : issuer);
14980
+ url.search = issuer.search;
14522
14981
  }
14523
- if (!response.ok) {
14524
- throw new Error(`HTTP ${response.status} trying to load well-known OAuth metadata`);
14982
+ let response = await tryMetadataDiscovery(url, protocolVersion, fetchFn);
14983
+ // If path-aware discovery fails with 404 and we're not already at root, try fallback to root discovery
14984
+ if (!(opts === null || opts === void 0 ? void 0 : opts.metadataUrl) && shouldAttemptFallback(response, issuer.pathname)) {
14985
+ const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
14986
+ response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
14525
14987
  }
14526
- return OAuthMetadataSchema.parse(await response.json());
14988
+ return response;
14989
+ }
14990
+ /**
14991
+ * Builds a list of discovery URLs to try for authorization server metadata.
14992
+ * URLs are returned in priority order:
14993
+ * 1. OAuth metadata at the given URL
14994
+ * 2. OAuth metadata at root (if URL has path)
14995
+ * 3. OIDC metadata endpoints
14996
+ */
14997
+ function buildDiscoveryUrls(authorizationServerUrl) {
14998
+ const url = typeof authorizationServerUrl === 'string' ? new URL(authorizationServerUrl) : authorizationServerUrl;
14999
+ const hasPath = url.pathname !== '/';
15000
+ const urlsToTry = [];
15001
+ if (!hasPath) {
15002
+ // Root path: https://example.com/.well-known/oauth-authorization-server
15003
+ urlsToTry.push({
15004
+ url: new URL('/.well-known/oauth-authorization-server', url.origin),
15005
+ type: 'oauth'
15006
+ });
15007
+ // OIDC: https://example.com/.well-known/openid-configuration
15008
+ urlsToTry.push({
15009
+ url: new URL(`/.well-known/openid-configuration`, url.origin),
15010
+ type: 'oidc'
15011
+ });
15012
+ return urlsToTry;
15013
+ }
15014
+ // Strip trailing slash from pathname to avoid double slashes
15015
+ let pathname = url.pathname;
15016
+ if (pathname.endsWith('/')) {
15017
+ pathname = pathname.slice(0, -1);
15018
+ }
15019
+ // 1. OAuth metadata at the given URL
15020
+ // Insert well-known before the path: https://example.com/.well-known/oauth-authorization-server/tenant1
15021
+ urlsToTry.push({
15022
+ url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url.origin),
15023
+ type: 'oauth'
15024
+ });
15025
+ // Root path: https://example.com/.well-known/oauth-authorization-server
15026
+ urlsToTry.push({
15027
+ url: new URL('/.well-known/oauth-authorization-server', url.origin),
15028
+ type: 'oauth'
15029
+ });
15030
+ // 3. OIDC metadata endpoints
15031
+ // RFC 8414 style: Insert /.well-known/openid-configuration before the path
15032
+ urlsToTry.push({
15033
+ url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
15034
+ type: 'oidc'
15035
+ });
15036
+ // OIDC Discovery 1.0 style: Append /.well-known/openid-configuration after the path
15037
+ urlsToTry.push({
15038
+ url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
15039
+ type: 'oidc'
15040
+ });
15041
+ return urlsToTry;
15042
+ }
15043
+ /**
15044
+ * Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
15045
+ * and OpenID Connect Discovery 1.0 specifications.
15046
+ *
15047
+ * This function implements a fallback strategy for authorization server discovery:
15048
+ * 1. Attempts RFC 8414 OAuth metadata discovery first
15049
+ * 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
15050
+ *
15051
+ * @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
15052
+ * protected resource metadata, or the MCP server's URL if the
15053
+ * metadata was not found.
15054
+ * @param options - Configuration options
15055
+ * @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
15056
+ * @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
15057
+ * @returns Promise resolving to authorization server metadata, or undefined if discovery fails
15058
+ */
15059
+ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION, } = {}) {
15060
+ var _a;
15061
+ const headers = { 'MCP-Protocol-Version': protocolVersion };
15062
+ // Get the list of URLs to try
15063
+ const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
15064
+ // Try each URL in order
15065
+ for (const { url: endpointUrl, type } of urlsToTry) {
15066
+ const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
15067
+ if (!response) {
15068
+ /**
15069
+ * CORS error occurred - don't throw as the endpoint may not allow CORS,
15070
+ * continue trying other possible endpoints
15071
+ */
15072
+ continue;
15073
+ }
15074
+ if (!response.ok) {
15075
+ // Continue looking for any 4xx response code.
15076
+ if (response.status >= 400 && response.status < 500) {
15077
+ continue; // Try next URL
15078
+ }
15079
+ throw new Error(`HTTP ${response.status} trying to load ${type === 'oauth' ? 'OAuth' : 'OpenID provider'} metadata from ${endpointUrl}`);
15080
+ }
15081
+ // Parse and validate based on type
15082
+ if (type === 'oauth') {
15083
+ return OAuthMetadataSchema.parse(await response.json());
15084
+ }
15085
+ else {
15086
+ const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
15087
+ // MCP spec requires OIDC providers to support S256 PKCE
15088
+ if (!((_a = metadata.code_challenge_methods_supported) === null || _a === void 0 ? void 0 : _a.includes('S256'))) {
15089
+ throw new Error(`Incompatible OIDC provider at ${endpointUrl}: does not support S256 code challenge method required by MCP specification`);
15090
+ }
15091
+ return metadata;
15092
+ }
15093
+ }
15094
+ return undefined;
14527
15095
  }
14528
15096
  /**
14529
15097
  * Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
@@ -14560,6 +15128,12 @@ async function startAuthorization(authorizationServerUrl, { metadata, clientInfo
14560
15128
  if (scope) {
14561
15129
  authorizationUrl.searchParams.set("scope", scope);
14562
15130
  }
15131
+ if (scope === null || scope === void 0 ? void 0 : scope.includes("offline_access")) {
15132
+ // if the request includes the OIDC-only "offline_access" scope,
15133
+ // we need to set the prompt to "consent" to ensure the user is prompted to grant offline access
15134
+ // https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
15135
+ authorizationUrl.searchParams.append("prompt", "consent");
15136
+ }
14563
15137
  if (resource) {
14564
15138
  authorizationUrl.searchParams.set("resource", resource.href);
14565
15139
  }
@@ -14567,50 +15141,73 @@ async function startAuthorization(authorizationServerUrl, { metadata, clientInfo
14567
15141
  }
14568
15142
  /**
14569
15143
  * Exchanges an authorization code for an access token with the given server.
15144
+ *
15145
+ * Supports multiple client authentication methods as specified in OAuth 2.1:
15146
+ * - Automatically selects the best authentication method based on server support
15147
+ * - Falls back to appropriate defaults when server metadata is unavailable
15148
+ *
15149
+ * @param authorizationServerUrl - The authorization server's base URL
15150
+ * @param options - Configuration object containing client info, auth code, etc.
15151
+ * @returns Promise resolving to OAuth tokens
15152
+ * @throws {Error} When token exchange fails or authentication is invalid
14570
15153
  */
14571
- async function exchangeAuthorization(authorizationServerUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, resource, }) {
15154
+ async function exchangeAuthorization(authorizationServerUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, resource, addClientAuthentication, fetchFn, }) {
15155
+ var _a;
14572
15156
  const grantType = "authorization_code";
14573
- let tokenUrl;
14574
- if (metadata) {
14575
- tokenUrl = new URL(metadata.token_endpoint);
14576
- if (metadata.grant_types_supported &&
14577
- !metadata.grant_types_supported.includes(grantType)) {
14578
- throw new Error(`Incompatible auth server: does not support grant type ${grantType}`);
14579
- }
14580
- }
14581
- else {
14582
- tokenUrl = new URL("/token", authorizationServerUrl);
15157
+ const tokenUrl = (metadata === null || metadata === void 0 ? void 0 : metadata.token_endpoint)
15158
+ ? new URL(metadata.token_endpoint)
15159
+ : new URL("/token", authorizationServerUrl);
15160
+ if ((metadata === null || metadata === void 0 ? void 0 : metadata.grant_types_supported) &&
15161
+ !metadata.grant_types_supported.includes(grantType)) {
15162
+ throw new Error(`Incompatible auth server: does not support grant type ${grantType}`);
14583
15163
  }
14584
15164
  // Exchange code for tokens
15165
+ const headers = new Headers({
15166
+ "Content-Type": "application/x-www-form-urlencoded",
15167
+ "Accept": "application/json",
15168
+ });
14585
15169
  const params = new URLSearchParams({
14586
15170
  grant_type: grantType,
14587
- client_id: clientInformation.client_id,
14588
15171
  code: authorizationCode,
14589
15172
  code_verifier: codeVerifier,
14590
15173
  redirect_uri: String(redirectUri),
14591
15174
  });
14592
- if (clientInformation.client_secret) {
14593
- params.set("client_secret", clientInformation.client_secret);
15175
+ if (addClientAuthentication) {
15176
+ addClientAuthentication(headers, params, authorizationServerUrl, metadata);
15177
+ }
15178
+ else {
15179
+ // Determine and apply client authentication method
15180
+ const supportedMethods = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.token_endpoint_auth_methods_supported) !== null && _a !== void 0 ? _a : [];
15181
+ const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
15182
+ applyClientAuthentication(authMethod, clientInformation, headers, params);
14594
15183
  }
14595
15184
  if (resource) {
14596
15185
  params.set("resource", resource.href);
14597
15186
  }
14598
- const response = await fetch(tokenUrl, {
15187
+ const response = await (fetchFn !== null && fetchFn !== void 0 ? fetchFn : fetch)(tokenUrl, {
14599
15188
  method: "POST",
14600
- headers: {
14601
- "Content-Type": "application/x-www-form-urlencoded",
14602
- },
15189
+ headers,
14603
15190
  body: params,
14604
15191
  });
14605
15192
  if (!response.ok) {
14606
- throw new Error(`Token exchange failed: HTTP ${response.status}`);
15193
+ throw await parseErrorResponse(response);
14607
15194
  }
14608
15195
  return OAuthTokensSchema.parse(await response.json());
14609
15196
  }
14610
15197
  /**
14611
15198
  * Exchange a refresh token for an updated access token.
15199
+ *
15200
+ * Supports multiple client authentication methods as specified in OAuth 2.1:
15201
+ * - Automatically selects the best authentication method based on server support
15202
+ * - Preserves the original refresh token if a new one is not returned
15203
+ *
15204
+ * @param authorizationServerUrl - The authorization server's base URL
15205
+ * @param options - Configuration object containing client info, refresh token, etc.
15206
+ * @returns Promise resolving to OAuth tokens (preserves original refresh_token if not replaced)
15207
+ * @throws {Error} When token refresh fails or authentication is invalid
14612
15208
  */
14613
- async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, }) {
15209
+ async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn, }) {
15210
+ var _a;
14614
15211
  const grantType = "refresh_token";
14615
15212
  let tokenUrl;
14616
15213
  if (metadata) {
@@ -14624,33 +15221,39 @@ async function refreshAuthorization(authorizationServerUrl, { metadata, clientIn
14624
15221
  tokenUrl = new URL("/token", authorizationServerUrl);
14625
15222
  }
14626
15223
  // Exchange refresh token
15224
+ const headers = new Headers({
15225
+ "Content-Type": "application/x-www-form-urlencoded",
15226
+ });
14627
15227
  const params = new URLSearchParams({
14628
15228
  grant_type: grantType,
14629
- client_id: clientInformation.client_id,
14630
15229
  refresh_token: refreshToken,
14631
15230
  });
14632
- if (clientInformation.client_secret) {
14633
- params.set("client_secret", clientInformation.client_secret);
15231
+ if (addClientAuthentication) {
15232
+ addClientAuthentication(headers, params, authorizationServerUrl, metadata);
15233
+ }
15234
+ else {
15235
+ // Determine and apply client authentication method
15236
+ const supportedMethods = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.token_endpoint_auth_methods_supported) !== null && _a !== void 0 ? _a : [];
15237
+ const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
15238
+ applyClientAuthentication(authMethod, clientInformation, headers, params);
14634
15239
  }
14635
15240
  if (resource) {
14636
15241
  params.set("resource", resource.href);
14637
15242
  }
14638
- const response = await fetch(tokenUrl, {
15243
+ const response = await (fetchFn !== null && fetchFn !== void 0 ? fetchFn : fetch)(tokenUrl, {
14639
15244
  method: "POST",
14640
- headers: {
14641
- "Content-Type": "application/x-www-form-urlencoded",
14642
- },
15245
+ headers,
14643
15246
  body: params,
14644
15247
  });
14645
15248
  if (!response.ok) {
14646
- throw new Error(`Token refresh failed: HTTP ${response.status}`);
15249
+ throw await parseErrorResponse(response);
14647
15250
  }
14648
15251
  return OAuthTokensSchema.parse({ refresh_token: refreshToken, ...(await response.json()) });
14649
15252
  }
14650
15253
  /**
14651
15254
  * Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
14652
15255
  */
14653
- async function registerClient(authorizationServerUrl, { metadata, clientMetadata, }) {
15256
+ async function registerClient(authorizationServerUrl, { metadata, clientMetadata, fetchFn, }) {
14654
15257
  let registrationUrl;
14655
15258
  if (metadata) {
14656
15259
  if (!metadata.registration_endpoint) {
@@ -14661,7 +15264,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
14661
15264
  else {
14662
15265
  registrationUrl = new URL("/register", authorizationServerUrl);
14663
15266
  }
14664
- const response = await fetch(registrationUrl, {
15267
+ const response = await (fetchFn !== null && fetchFn !== void 0 ? fetchFn : fetch)(registrationUrl, {
14665
15268
  method: "POST",
14666
15269
  headers: {
14667
15270
  "Content-Type": "application/json",
@@ -14669,7 +15272,7 @@ async function registerClient(authorizationServerUrl, { metadata, clientMetadata
14669
15272
  body: JSON.stringify(clientMetadata),
14670
15273
  });
14671
15274
  if (!response.ok) {
14672
- throw new Error(`Dynamic client registration failed: HTTP ${response.status}`);
15275
+ throw await parseErrorResponse(response);
14673
15276
  }
14674
15277
  return OAuthClientInformationFullSchema.parse(await response.json());
14675
15278
  }
@@ -14764,7 +15367,7 @@ function splitLines(chunk) {
14764
15367
  const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
14765
15368
  `, searchIndex);
14766
15369
  let lineEnd = -1;
14767
- if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
15370
+ if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
14768
15371
  incompleteLine = chunk.slice(searchIndex);
14769
15372
  break;
14770
15373
  } else {
@@ -14835,7 +15438,7 @@ class StreamableHTTPClientTransport {
14835
15438
  }
14836
15439
  let result;
14837
15440
  try {
14838
- result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl });
15441
+ result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
14839
15442
  }
14840
15443
  catch (error) {
14841
15444
  (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
@@ -14896,7 +15499,7 @@ class StreamableHTTPClientTransport {
14896
15499
  }
14897
15500
  throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
14898
15501
  }
14899
- this._handleSseStream(response.body, options);
15502
+ this._handleSseStream(response.body, options, true);
14900
15503
  }
14901
15504
  catch (error) {
14902
15505
  (_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error);
@@ -14956,7 +15559,7 @@ class StreamableHTTPClientTransport {
14956
15559
  });
14957
15560
  }, delay);
14958
15561
  }
14959
- _handleSseStream(stream, options) {
15562
+ _handleSseStream(stream, options, isReconnectable) {
14960
15563
  if (!stream) {
14961
15564
  return;
14962
15565
  }
@@ -15000,19 +15603,19 @@ class StreamableHTTPClientTransport {
15000
15603
  // Handle stream errors - likely a network disconnect
15001
15604
  (_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, new Error(`SSE stream disconnected: ${error}`));
15002
15605
  // Attempt to reconnect if the stream disconnects unexpectedly and we aren't closing
15003
- if (this._abortController && !this._abortController.signal.aborted) {
15606
+ if (isReconnectable &&
15607
+ this._abortController &&
15608
+ !this._abortController.signal.aborted) {
15004
15609
  // Use the exponential backoff reconnection strategy
15005
- if (lastEventId !== undefined) {
15006
- try {
15007
- this._scheduleReconnection({
15008
- resumptionToken: lastEventId,
15009
- onresumptiontoken,
15010
- replayMessageId
15011
- }, 0);
15012
- }
15013
- catch (error) {
15014
- (_d = this.onerror) === null || _d === void 0 ? void 0 : _d.call(this, new Error(`Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`));
15015
- }
15610
+ try {
15611
+ this._scheduleReconnection({
15612
+ resumptionToken: lastEventId,
15613
+ onresumptiontoken,
15614
+ replayMessageId
15615
+ }, 0);
15616
+ }
15617
+ catch (error) {
15618
+ (_d = this.onerror) === null || _d === void 0 ? void 0 : _d.call(this, new Error(`Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`));
15016
15619
  }
15017
15620
  }
15018
15621
  }
@@ -15032,7 +15635,7 @@ class StreamableHTTPClientTransport {
15032
15635
  if (!this._authProvider) {
15033
15636
  throw new UnauthorizedError("No auth provider");
15034
15637
  }
15035
- const result = await auth(this._authProvider, { serverUrl: this._url, authorizationCode, resourceMetadataUrl: this._resourceMetadataUrl });
15638
+ const result = await auth(this._authProvider, { serverUrl: this._url, authorizationCode, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
15036
15639
  if (result !== "AUTHORIZED") {
15037
15640
  throw new UnauthorizedError("Failed to authorize");
15038
15641
  }
@@ -15071,7 +15674,7 @@ class StreamableHTTPClientTransport {
15071
15674
  if (!response.ok) {
15072
15675
  if (response.status === 401 && this._authProvider) {
15073
15676
  this._resourceMetadataUrl = extractResourceMetadataUrl(response);
15074
- const result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl });
15677
+ const result = await auth(this._authProvider, { serverUrl: this._url, resourceMetadataUrl: this._resourceMetadataUrl, fetchFn: this._fetch });
15075
15678
  if (result !== "AUTHORIZED") {
15076
15679
  throw new UnauthorizedError();
15077
15680
  }
@@ -15101,7 +15704,7 @@ class StreamableHTTPClientTransport {
15101
15704
  // Handle SSE stream responses for requests
15102
15705
  // We use the same handler as standalone streams, which now supports
15103
15706
  // reconnection with the last event ID
15104
- this._handleSseStream(response.body, { onresumptiontoken });
15707
+ this._handleSseStream(response.body, { onresumptiontoken }, false);
15105
15708
  }
15106
15709
  else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json")) {
15107
15710
  // For non-streaming servers, we might get direct JSON responses