@ai-sdk/mcp 1.0.74 → 1.0.75

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,12 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 1.0.75
4
+
5
+ ### Patch Changes
6
+
7
+ - 878bdb9: Apply MCP scope selection to dynamic client registration as well as authorization.
8
+ - 204ce6c: fix(mcp): reject private OAuth endpoints before sending credentials
9
+
3
10
  ## 1.0.74
4
11
 
5
12
  ### Patch Changes
package/dist/index.js CHANGED
@@ -564,6 +564,23 @@ var UnauthorizedError = class extends Error {
564
564
  function normalizeUrl(url) {
565
565
  return new URL(url).href;
566
566
  }
567
+ function isOAuthLoopbackHost(hostname) {
568
+ const normalized = hostname.toLowerCase().replace(/\.+$/, "");
569
+ return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "127.0.0.1" || normalized === "[::1]" || normalized === "::1";
570
+ }
571
+ function assertSafeOAuthEndpoint(endpointUrl) {
572
+ if ((endpointUrl.protocol === "http:" || endpointUrl.protocol === "https:") && isOAuthLoopbackHost(endpointUrl.hostname)) {
573
+ return;
574
+ }
575
+ try {
576
+ (0, import_provider_utils2.validateDownloadUrl)(endpointUrl.href);
577
+ } catch (error) {
578
+ throw new MCPClientOAuthError({
579
+ message: `OAuth endpoint URL is not allowed: ${endpointUrl.href}`,
580
+ cause: error
581
+ });
582
+ }
583
+ }
567
584
  function createAuthorizationServerInformation(authorizationServerUrl, metadata) {
568
585
  return {
569
586
  authorizationServerUrl: normalizeUrl(authorizationServerUrl),
@@ -996,6 +1013,7 @@ async function exchangeAuthorization(authorizationServerUrl, {
996
1013
  var _a3;
997
1014
  const grantType = "authorization_code";
998
1015
  const tokenUrl = (metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
1016
+ assertSafeOAuthEndpoint(tokenUrl);
999
1017
  if ((metadata == null ? void 0 : metadata.grant_types_supported) && !metadata.grant_types_supported.includes(grantType)) {
1000
1018
  throw new Error(
1001
1019
  `Incompatible auth server: does not support grant type ${grantType}`
@@ -1032,7 +1050,8 @@ async function exchangeAuthorization(authorizationServerUrl, {
1032
1050
  const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
1033
1051
  method: "POST",
1034
1052
  headers,
1035
- body: params
1053
+ body: params,
1054
+ redirect: "error"
1036
1055
  });
1037
1056
  if (!response.ok) {
1038
1057
  throw await parseErrorResponse(response);
@@ -1060,6 +1079,7 @@ async function refreshAuthorization(authorizationServerUrl, {
1060
1079
  } else {
1061
1080
  tokenUrl = new URL("/token", authorizationServerUrl);
1062
1081
  }
1082
+ assertSafeOAuthEndpoint(tokenUrl);
1063
1083
  const headers = new Headers({
1064
1084
  "Content-Type": "application/x-www-form-urlencoded",
1065
1085
  Accept: "application/json"
@@ -1089,7 +1109,8 @@ async function refreshAuthorization(authorizationServerUrl, {
1089
1109
  const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
1090
1110
  method: "POST",
1091
1111
  headers,
1092
- body: params
1112
+ body: params,
1113
+ redirect: "error"
1093
1114
  });
1094
1115
  if (!response.ok) {
1095
1116
  throw await parseErrorResponse(response);
@@ -1115,12 +1136,14 @@ async function registerClient(authorizationServerUrl, {
1115
1136
  } else {
1116
1137
  registrationUrl = new URL("/register", authorizationServerUrl);
1117
1138
  }
1139
+ assertSafeOAuthEndpoint(registrationUrl);
1118
1140
  const response = await (fetchFn != null ? fetchFn : fetch)(registrationUrl, {
1119
1141
  method: "POST",
1120
1142
  headers: {
1121
1143
  "Content-Type": "application/json"
1122
1144
  },
1123
- body: JSON.stringify(clientMetadata)
1145
+ body: JSON.stringify(clientMetadata),
1146
+ redirect: "error"
1124
1147
  });
1125
1148
  if (!response.ok) {
1126
1149
  throw await parseErrorResponse(response);
@@ -1206,6 +1229,12 @@ async function authInternal(provider, {
1206
1229
  }
1207
1230
  );
1208
1231
  const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
1232
+ const clientMetadata = provider.clientMetadata;
1233
+ const selectedScope = selectScope({
1234
+ scope,
1235
+ resourceMetadata,
1236
+ clientMetadata
1237
+ });
1209
1238
  let clientInformation = await Promise.resolve(provider.clientInformation());
1210
1239
  if (!clientInformation) {
1211
1240
  if (authorizationCode !== void 0) {
@@ -1220,7 +1249,10 @@ async function authInternal(provider, {
1220
1249
  }
1221
1250
  const fullInformation = await registerClient(authorizationServerUrl, {
1222
1251
  metadata,
1223
- clientMetadata: provider.clientMetadata,
1252
+ clientMetadata: {
1253
+ ...clientMetadata,
1254
+ scope: selectedScope
1255
+ },
1224
1256
  fetchFn
1225
1257
  });
1226
1258
  clientInformation = addAuthorizationServerInformationToClientInformation(
@@ -1324,11 +1356,7 @@ async function authInternal(provider, {
1324
1356
  clientInformation,
1325
1357
  state,
1326
1358
  redirectUrl: provider.redirectUrl,
1327
- scope: selectScope({
1328
- scope,
1329
- resourceMetadata,
1330
- clientMetadata: provider.clientMetadata
1331
- }),
1359
+ scope: selectedScope,
1332
1360
  resource
1333
1361
  }
1334
1362
  );