@ai-sdk/mcp 1.0.96 → 1.0.98

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,18 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 1.0.98
4
+
5
+ ### Patch Changes
6
+
7
+ - b7927f6: fix(mcp): bind OAuth client credentials to their authorization server, including when the selected server is approved by `validateAuthorizationServerURL`
8
+
9
+ ## 1.0.97
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies [5aa3086]
14
+ - @ai-sdk/provider-utils@4.0.61
15
+
3
16
  ## 1.0.96
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -119,6 +119,7 @@ declare const OAuthClientInformationSchema: z.ZodObject<{
119
119
  client_secret: z.ZodOptional<z.ZodString>;
120
120
  client_id_issued_at: z.ZodOptional<z.ZodNumber>;
121
121
  client_secret_expires_at: z.ZodOptional<z.ZodNumber>;
122
+ issuer: z.ZodOptional<z.ZodString>;
122
123
  authorization_server: z.ZodOptional<z.ZodString>;
123
124
  token_endpoint: z.ZodOptional<z.ZodString>;
124
125
  }, z.core.$strip>;
@@ -195,6 +196,11 @@ interface OAuthClientProvider {
195
196
  }): void | Promise<void>;
196
197
  get redirectUrl(): string | URL;
197
198
  get clientMetadata(): OAuthClientMetadata;
199
+ /**
200
+ * Returns client credentials. Pre-registered confidential clients must specify
201
+ * their authorization server's `issuer` or provide stored authorization server
202
+ * information. `validateAuthorizationServerURL` does not replace this binding.
203
+ */
198
204
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
199
205
  /**
200
206
  * Returns whether the current client information was obtained through
@@ -212,6 +218,7 @@ interface OAuthClientProvider {
212
218
  /**
213
219
  * Validates an authorization server URL discovered from MCP protected resource
214
220
  * metadata before the client fetches its OAuth metadata.
221
+ * This additional restriction does not bind client credentials to that server.
215
222
  */
216
223
  validateAuthorizationServerURL?(serverUrl: string | URL, authorizationServerUrl: string | URL): void | Promise<void>;
217
224
  state?(): string | Promise<string>;
package/dist/index.d.ts CHANGED
@@ -119,6 +119,7 @@ declare const OAuthClientInformationSchema: z.ZodObject<{
119
119
  client_secret: z.ZodOptional<z.ZodString>;
120
120
  client_id_issued_at: z.ZodOptional<z.ZodNumber>;
121
121
  client_secret_expires_at: z.ZodOptional<z.ZodNumber>;
122
+ issuer: z.ZodOptional<z.ZodString>;
122
123
  authorization_server: z.ZodOptional<z.ZodString>;
123
124
  token_endpoint: z.ZodOptional<z.ZodString>;
124
125
  }, z.core.$strip>;
@@ -195,6 +196,11 @@ interface OAuthClientProvider {
195
196
  }): void | Promise<void>;
196
197
  get redirectUrl(): string | URL;
197
198
  get clientMetadata(): OAuthClientMetadata;
199
+ /**
200
+ * Returns client credentials. Pre-registered confidential clients must specify
201
+ * their authorization server's `issuer` or provide stored authorization server
202
+ * information. `validateAuthorizationServerURL` does not replace this binding.
203
+ */
198
204
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
199
205
  /**
200
206
  * Returns whether the current client information was obtained through
@@ -212,6 +218,7 @@ interface OAuthClientProvider {
212
218
  /**
213
219
  * Validates an authorization server URL discovered from MCP protected resource
214
220
  * metadata before the client fetches its OAuth metadata.
221
+ * This additional restriction does not bind client credentials to that server.
215
222
  */
216
223
  validateAuthorizationServerURL?(serverUrl: string | URL, authorizationServerUrl: string | URL): void | Promise<void>;
217
224
  state?(): string | Promise<string>;
package/dist/index.js CHANGED
@@ -459,6 +459,7 @@ var OAuthClientInformationSchema = import_v43.z.object({
459
459
  client_secret: import_v43.z.string().optional(),
460
460
  client_id_issued_at: import_v43.z.number().optional(),
461
461
  client_secret_expires_at: import_v43.z.number().optional(),
462
+ issuer: SafeUrlSchema.optional(),
462
463
  authorization_server: SafeUrlSchema.optional(),
463
464
  token_endpoint: SafeUrlSchema.optional()
464
465
  }).strip();
@@ -1234,10 +1235,16 @@ async function auth(provider, options) {
1234
1235
  await ((_b3 = provider.invalidateCredentials) == null ? void 0 : _b3.call(provider, "all"));
1235
1236
  return await authInternal(provider, options);
1236
1237
  } else if (error instanceof InvalidGrantError && refreshAttempt.tokens) {
1238
+ const retryAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(refreshAttempt.tokens);
1237
1239
  await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens", {
1238
1240
  tokens: refreshAttempt.tokens
1239
1241
  }));
1240
- return await authInternal(provider, options);
1242
+ return await authInternal(
1243
+ provider,
1244
+ options,
1245
+ void 0,
1246
+ retryAuthorizationServerInformation
1247
+ );
1241
1248
  }
1242
1249
  throw error;
1243
1250
  }
@@ -1270,8 +1277,8 @@ async function authInternal(provider, {
1270
1277
  scope,
1271
1278
  resourceMetadataUrl,
1272
1279
  fetchFn
1273
- }, refreshAttempt) {
1274
- var _a3, _b3, _c;
1280
+ }, refreshAttempt, retryAuthorizationServerInformation) {
1281
+ var _a3, _b3, _c, _d, _e;
1275
1282
  let resourceMetadata;
1276
1283
  let authorizationServerUrl;
1277
1284
  let clientInformation;
@@ -1326,6 +1333,12 @@ async function authInternal(provider, {
1326
1333
  }
1327
1334
  );
1328
1335
  const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
1336
+ if (retryAuthorizationServerInformation) {
1337
+ assertAuthorizationServerInformationMatches({
1338
+ storedAuthorizationServerInformation: retryAuthorizationServerInformation,
1339
+ currentAuthorizationServerInformation
1340
+ });
1341
+ }
1329
1342
  const clientMetadata = provider.clientMetadata;
1330
1343
  const selectedScope = selectScope({
1331
1344
  scope,
@@ -1335,6 +1348,37 @@ async function authInternal(provider, {
1335
1348
  if (authorizationCode === void 0) {
1336
1349
  clientInformation = await Promise.resolve(provider.clientInformation());
1337
1350
  }
1351
+ const tokens = authorizationCode === void 0 ? await provider.tokens() : void 0;
1352
+ if (clientInformation) {
1353
+ if (clientInformation.issuer != null && clientInformation.issuer !== ((_c = metadata == null ? void 0 : metadata.issuer) != null ? _c : authorizationServerUrl.toString())) {
1354
+ throw new MCPClientOAuthError({
1355
+ message: "OAuth authorization server does not match the issuer of the client credentials"
1356
+ });
1357
+ }
1358
+ const clientAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(clientInformation);
1359
+ if (clientAuthorizationServerInformation) {
1360
+ assertAuthorizationServerInformationMatches({
1361
+ storedAuthorizationServerInformation: clientAuthorizationServerInformation,
1362
+ currentAuthorizationServerInformation
1363
+ });
1364
+ }
1365
+ const storedAuthorizationServerInformation = (_d = callbackAuthorizationServerInformation != null ? callbackAuthorizationServerInformation : await getStoredAuthorizationServerInformation({
1366
+ provider,
1367
+ clientInformation,
1368
+ tokens
1369
+ })) != null ? _d : retryAuthorizationServerInformation;
1370
+ if (storedAuthorizationServerInformation) {
1371
+ assertAuthorizationServerInformationMatches({
1372
+ storedAuthorizationServerInformation,
1373
+ currentAuthorizationServerInformation
1374
+ });
1375
+ }
1376
+ if ((clientInformation.client_secret != null || provider.addClientAuthentication) && clientInformation.issuer == null && !storedAuthorizationServerInformation) {
1377
+ throw new MCPClientOAuthError({
1378
+ message: "OAuth client credentials must be bound to an authorization server: configure their issuer or store authorization server information"
1379
+ });
1380
+ }
1381
+ }
1338
1382
  if (!clientInformation) {
1339
1383
  if (authorizationCode !== void 0) {
1340
1384
  throw new Error(
@@ -1401,7 +1445,6 @@ async function authInternal(provider, {
1401
1445
  );
1402
1446
  return "AUTHORIZED";
1403
1447
  }
1404
- const tokens = await provider.tokens();
1405
1448
  if (tokens == null ? void 0 : tokens.refresh_token) {
1406
1449
  const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
1407
1450
  provider,
@@ -1414,7 +1457,7 @@ async function authInternal(provider, {
1414
1457
  currentAuthorizationServerInformation
1415
1458
  });
1416
1459
  } else {
1417
- await ((_c = provider.invalidateCredentials) == null ? void 0 : _c.call(provider, "tokens", {
1460
+ await ((_e = provider.invalidateCredentials) == null ? void 0 : _e.call(provider, "tokens", {
1418
1461
  tokens: { ...tokens }
1419
1462
  }));
1420
1463
  }