@ai-sdk/mcp 1.0.90 → 1.0.92

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 1.0.92
4
+
5
+ ### Patch Changes
6
+
7
+ - ff05827: fix(mcp): authorization server paths beginning with repeated slashes should not bypass authorization server validation
8
+
9
+ ## 1.0.91
10
+
11
+ ### Patch Changes
12
+
13
+ - 5267a7a: Preserve stored OAuth credentials when an authorization-code exchange returns `invalid_grant`, without retrying the rejected code.
14
+
15
+ Add optional token context to `OAuthClientProvider.invalidateCredentials` so providers sharing storage can atomically delete only the rejected token generation and preserve tokens saved by a concurrent refresh.
16
+
3
17
  ## 1.0.90
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -184,8 +184,15 @@ interface OAuthClientProvider {
184
184
  * If implemented, provides a way for the client to invalidate (e.g. delete) the specified
185
185
  * credentials, in the case where the server has indicated that they are no longer valid.
186
186
  * This avoids requiring the user to intervene manually.
187
+ *
188
+ * For token invalidation, context identifies the token generation being invalidated
189
+ * when available. Providers sharing storage must atomically compare and delete
190
+ * that generation so a concurrent refresh's tokens are preserved. Omitting or
191
+ * ignoring context retains unconditional invalidation.
187
192
  */
188
- invalidateCredentials?(scope: 'all' | 'client' | 'tokens' | 'verifier'): void | Promise<void>;
193
+ invalidateCredentials?(scope: 'all' | 'client' | 'tokens' | 'verifier', context?: {
194
+ tokens: OAuthTokens;
195
+ }): void | Promise<void>;
189
196
  get redirectUrl(): string | URL;
190
197
  get clientMetadata(): OAuthClientMetadata;
191
198
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
package/dist/index.d.ts CHANGED
@@ -184,8 +184,15 @@ interface OAuthClientProvider {
184
184
  * If implemented, provides a way for the client to invalidate (e.g. delete) the specified
185
185
  * credentials, in the case where the server has indicated that they are no longer valid.
186
186
  * This avoids requiring the user to intervene manually.
187
+ *
188
+ * For token invalidation, context identifies the token generation being invalidated
189
+ * when available. Providers sharing storage must atomically compare and delete
190
+ * that generation so a concurrent refresh's tokens are preserved. Omitting or
191
+ * ignoring context retains unconditional invalidation.
187
192
  */
188
- invalidateCredentials?(scope: 'all' | 'client' | 'tokens' | 'verifier'): void | Promise<void>;
193
+ invalidateCredentials?(scope: 'all' | 'client' | 'tokens' | 'verifier', context?: {
194
+ tokens: OAuthTokens;
195
+ }): void | Promise<void>;
189
196
  get redirectUrl(): string | URL;
190
197
  get clientMetadata(): OAuthClientMetadata;
191
198
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
package/dist/index.js CHANGED
@@ -860,8 +860,10 @@ function buildDiscoveryUrls(authorizationServerUrl) {
860
860
  type: "oidc",
861
861
  expectedIssuer: pathIssuer
862
862
  });
863
+ const oidcDiscoveryUrl = new URL(url.origin);
864
+ oidcDiscoveryUrl.pathname = `${pathname}/.well-known/openid-configuration`;
863
865
  urlsToTry.push({
864
- url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
866
+ url: oidcDiscoveryUrl,
865
867
  type: "oidc",
866
868
  expectedIssuer: pathIssuer
867
869
  });
@@ -882,7 +884,13 @@ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
882
884
  } = {}) {
883
885
  var _a3;
884
886
  const headers = { "MCP-Protocol-Version": protocolVersion };
887
+ const authorizationServerOrigin = new URL(authorizationServerUrl).origin;
885
888
  const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
889
+ if (urlsToTry.some(({ url }) => url.origin !== authorizationServerOrigin)) {
890
+ throw new MCPClientOAuthError({
891
+ message: "OAuth discovery URL changed authorization-server origin"
892
+ });
893
+ }
886
894
  for (const { url: endpointUrl, type, expectedIssuer } of urlsToTry) {
887
895
  const response = await fetchWithCorsRetry(
888
896
  endpointUrl,
@@ -1215,8 +1223,9 @@ async function registerClient(authorizationServerUrl, {
1215
1223
  }
1216
1224
  async function auth(provider, options) {
1217
1225
  var _a3, _b3, _c;
1226
+ const refreshAttempt = {};
1218
1227
  try {
1219
- return await authInternal(provider, options);
1228
+ return await authInternal(provider, options, refreshAttempt);
1220
1229
  } catch (error) {
1221
1230
  if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
1222
1231
  if (options.authorizationCode !== void 0 || !await ((_a3 = provider.isClientInformationDynamicallyRegistered) == null ? void 0 : _a3.call(provider))) {
@@ -1224,8 +1233,10 @@ async function auth(provider, options) {
1224
1233
  }
1225
1234
  await ((_b3 = provider.invalidateCredentials) == null ? void 0 : _b3.call(provider, "all"));
1226
1235
  return await authInternal(provider, options);
1227
- } else if (error instanceof InvalidGrantError) {
1228
- await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens"));
1236
+ } else if (error instanceof InvalidGrantError && refreshAttempt.tokens) {
1237
+ await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens", {
1238
+ tokens: refreshAttempt.tokens
1239
+ }));
1229
1240
  return await authInternal(provider, options);
1230
1241
  }
1231
1242
  throw error;
@@ -1259,7 +1270,7 @@ async function authInternal(provider, {
1259
1270
  scope,
1260
1271
  resourceMetadataUrl,
1261
1272
  fetchFn
1262
- }) {
1273
+ }, refreshAttempt) {
1263
1274
  var _a3, _b3, _c;
1264
1275
  let resourceMetadata;
1265
1276
  let authorizationServerUrl;
@@ -1403,10 +1414,15 @@ async function authInternal(provider, {
1403
1414
  currentAuthorizationServerInformation
1404
1415
  });
1405
1416
  } else {
1406
- await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens"));
1417
+ await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens", {
1418
+ tokens: { ...tokens }
1419
+ }));
1407
1420
  }
1408
1421
  try {
1409
1422
  if (storedAuthorizationServerInformation) {
1423
+ if (refreshAttempt) {
1424
+ refreshAttempt.tokens = { ...tokens };
1425
+ }
1410
1426
  const newTokens = await refreshAuthorization(authorizationServerUrl, {
1411
1427
  metadata,
1412
1428
  clientInformation,