@ai-sdk/mcp 2.0.36 → 2.0.39
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 +27 -0
- package/dist/index.js +51 -13
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/tool/mcp-client.ts +11 -2
- package/src/tool/oauth.ts +62 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @ai-sdk/mcp
|
|
2
2
|
|
|
3
|
+
## 2.0.39
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [3e125ba]
|
|
8
|
+
- @ai-sdk/provider-utils@5.0.32
|
|
9
|
+
|
|
10
|
+
## 2.0.38
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- bf591f0: Apply MCP scope selection to dynamic client registration as well as authorization.
|
|
15
|
+
- fe69342: fix(mcp): reject private OAuth endpoints before sending credentials
|
|
16
|
+
- Updated dependencies [a9782e1]
|
|
17
|
+
- Updated dependencies [35841f5]
|
|
18
|
+
- Updated dependencies [d2f3353]
|
|
19
|
+
- @ai-sdk/provider-utils@5.0.31
|
|
20
|
+
|
|
21
|
+
## 2.0.37
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 1175434: Fetch all paginated tool definitions when creating an MCP tool set.
|
|
26
|
+
- Updated dependencies [591d25b]
|
|
27
|
+
- @ai-sdk/provider@4.0.8
|
|
28
|
+
- @ai-sdk/provider-utils@5.0.30
|
|
29
|
+
|
|
3
30
|
## 2.0.36
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -542,7 +542,10 @@ function checkResourceAllowed({
|
|
|
542
542
|
}
|
|
543
543
|
|
|
544
544
|
// src/tool/oauth.ts
|
|
545
|
-
import {
|
|
545
|
+
import {
|
|
546
|
+
parseJSON as parseJSON2,
|
|
547
|
+
validateDownloadUrl
|
|
548
|
+
} from "@ai-sdk/provider-utils";
|
|
546
549
|
var UnauthorizedError = class extends Error {
|
|
547
550
|
constructor(message = "Unauthorized") {
|
|
548
551
|
super(message);
|
|
@@ -552,6 +555,23 @@ var UnauthorizedError = class extends Error {
|
|
|
552
555
|
function normalizeUrl(url) {
|
|
553
556
|
return new URL(url).href;
|
|
554
557
|
}
|
|
558
|
+
function isOAuthLoopbackHost(hostname) {
|
|
559
|
+
const normalized = hostname.toLowerCase().replace(/\.+$/, "");
|
|
560
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "127.0.0.1" || normalized === "[::1]" || normalized === "::1";
|
|
561
|
+
}
|
|
562
|
+
function assertSafeOAuthEndpoint(endpointUrl) {
|
|
563
|
+
if ((endpointUrl.protocol === "http:" || endpointUrl.protocol === "https:") && isOAuthLoopbackHost(endpointUrl.hostname)) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
validateDownloadUrl(endpointUrl.href);
|
|
568
|
+
} catch (error) {
|
|
569
|
+
throw new MCPClientOAuthError({
|
|
570
|
+
message: `OAuth endpoint URL is not allowed: ${endpointUrl.href}`,
|
|
571
|
+
cause: error
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
555
575
|
function validateAuthorizationResponseIssuer({
|
|
556
576
|
callbackIssuer,
|
|
557
577
|
expectedIssuer
|
|
@@ -1000,6 +1020,7 @@ async function exchangeAuthorization(authorizationServerUrl, {
|
|
|
1000
1020
|
var _a3;
|
|
1001
1021
|
const grantType = "authorization_code";
|
|
1002
1022
|
const tokenUrl = (metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
|
|
1023
|
+
assertSafeOAuthEndpoint(tokenUrl);
|
|
1003
1024
|
if ((metadata == null ? void 0 : metadata.grant_types_supported) && !metadata.grant_types_supported.includes(grantType)) {
|
|
1004
1025
|
throw new Error(
|
|
1005
1026
|
`Incompatible auth server: does not support grant type ${grantType}`
|
|
@@ -1036,7 +1057,8 @@ async function exchangeAuthorization(authorizationServerUrl, {
|
|
|
1036
1057
|
const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
|
|
1037
1058
|
method: "POST",
|
|
1038
1059
|
headers,
|
|
1039
|
-
body: params
|
|
1060
|
+
body: params,
|
|
1061
|
+
redirect: "error"
|
|
1040
1062
|
});
|
|
1041
1063
|
if (!response.ok) {
|
|
1042
1064
|
throw await parseErrorResponse(response);
|
|
@@ -1064,6 +1086,7 @@ async function refreshAuthorization(authorizationServerUrl, {
|
|
|
1064
1086
|
} else {
|
|
1065
1087
|
tokenUrl = new URL("/token", authorizationServerUrl);
|
|
1066
1088
|
}
|
|
1089
|
+
assertSafeOAuthEndpoint(tokenUrl);
|
|
1067
1090
|
const headers = new Headers({
|
|
1068
1091
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
1069
1092
|
Accept: "application/json"
|
|
@@ -1093,7 +1116,8 @@ async function refreshAuthorization(authorizationServerUrl, {
|
|
|
1093
1116
|
const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
|
|
1094
1117
|
method: "POST",
|
|
1095
1118
|
headers,
|
|
1096
|
-
body: params
|
|
1119
|
+
body: params,
|
|
1120
|
+
redirect: "error"
|
|
1097
1121
|
});
|
|
1098
1122
|
if (!response.ok) {
|
|
1099
1123
|
throw await parseErrorResponse(response);
|
|
@@ -1120,6 +1144,7 @@ async function registerClient(authorizationServerUrl, {
|
|
|
1120
1144
|
} else {
|
|
1121
1145
|
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
1122
1146
|
}
|
|
1147
|
+
assertSafeOAuthEndpoint(registrationUrl);
|
|
1123
1148
|
const applicationType = (_a3 = clientMetadata.application_type) != null ? _a3 : inferOAuthApplicationType(clientMetadata.redirect_uris);
|
|
1124
1149
|
const response = await (fetchFn != null ? fetchFn : fetch)(registrationUrl, {
|
|
1125
1150
|
method: "POST",
|
|
@@ -1129,7 +1154,8 @@ async function registerClient(authorizationServerUrl, {
|
|
|
1129
1154
|
body: JSON.stringify({
|
|
1130
1155
|
...clientMetadata,
|
|
1131
1156
|
application_type: applicationType
|
|
1132
|
-
})
|
|
1157
|
+
}),
|
|
1158
|
+
redirect: "error"
|
|
1133
1159
|
});
|
|
1134
1160
|
if (!response.ok) {
|
|
1135
1161
|
throw await parseErrorResponse(response);
|
|
@@ -1139,7 +1165,7 @@ async function registerClient(authorizationServerUrl, {
|
|
|
1139
1165
|
function inferOAuthApplicationType(redirectUris) {
|
|
1140
1166
|
const isNativeRedirectUri = (redirectUri) => {
|
|
1141
1167
|
const url = new URL(redirectUri);
|
|
1142
|
-
return (url.protocol === "http:" || url.protocol === "https:") && (url.hostname
|
|
1168
|
+
return (url.protocol === "http:" || url.protocol === "https:") && isOAuthLoopbackHost(url.hostname) || url.protocol !== "http:" && url.protocol !== "https:";
|
|
1143
1169
|
};
|
|
1144
1170
|
return redirectUris.every(isNativeRedirectUri) ? "native" : "web";
|
|
1145
1171
|
}
|
|
@@ -1223,6 +1249,12 @@ async function authInternal(provider, {
|
|
|
1223
1249
|
}
|
|
1224
1250
|
);
|
|
1225
1251
|
const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
|
|
1252
|
+
const clientMetadata = provider.clientMetadata;
|
|
1253
|
+
const selectedScope = selectScope({
|
|
1254
|
+
scope,
|
|
1255
|
+
resourceMetadata,
|
|
1256
|
+
clientMetadata
|
|
1257
|
+
});
|
|
1226
1258
|
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1227
1259
|
if ((clientInformation == null ? void 0 : clientInformation.issuer) != null) {
|
|
1228
1260
|
const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
@@ -1249,7 +1281,10 @@ async function authInternal(provider, {
|
|
|
1249
1281
|
}
|
|
1250
1282
|
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
1251
1283
|
metadata,
|
|
1252
|
-
clientMetadata:
|
|
1284
|
+
clientMetadata: {
|
|
1285
|
+
...clientMetadata,
|
|
1286
|
+
scope: selectedScope
|
|
1287
|
+
},
|
|
1253
1288
|
fetchFn
|
|
1254
1289
|
});
|
|
1255
1290
|
clientInformation = addAuthorizationServerInformationToClientInformation(
|
|
@@ -1357,11 +1392,7 @@ async function authInternal(provider, {
|
|
|
1357
1392
|
clientInformation,
|
|
1358
1393
|
state,
|
|
1359
1394
|
redirectUrl: provider.redirectUrl,
|
|
1360
|
-
scope:
|
|
1361
|
-
scope,
|
|
1362
|
-
resourceMetadata,
|
|
1363
|
-
clientMetadata: provider.clientMetadata
|
|
1364
|
-
}),
|
|
1395
|
+
scope: selectedScope,
|
|
1365
1396
|
resource
|
|
1366
1397
|
}
|
|
1367
1398
|
);
|
|
@@ -3051,8 +3082,15 @@ var DefaultMCPClient = class {
|
|
|
3051
3082
|
async tools({
|
|
3052
3083
|
schemas = "automatic"
|
|
3053
3084
|
} = {}) {
|
|
3054
|
-
|
|
3055
|
-
|
|
3085
|
+
let definitions = await this.listTools();
|
|
3086
|
+
const tools = [...definitions.tools];
|
|
3087
|
+
while (definitions.nextCursor != null) {
|
|
3088
|
+
definitions = await this.listTools({
|
|
3089
|
+
params: { cursor: definitions.nextCursor }
|
|
3090
|
+
});
|
|
3091
|
+
tools.push(...definitions.tools);
|
|
3092
|
+
}
|
|
3093
|
+
return this.toolsFromDefinitions({ ...definitions, tools }, {
|
|
3056
3094
|
schemas
|
|
3057
3095
|
});
|
|
3058
3096
|
}
|