@ai-sdk/mcp 2.0.0-beta.2 → 2.0.0-beta.21
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 +149 -8
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +64 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +61 -19
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-stdio/index.js +3 -3
- package/dist/mcp-stdio/index.mjs +1 -1
- package/package.json +6 -8
- package/src/tool/mcp-client.ts +6 -2
- package/src/tool/mcp-http-transport.ts +17 -3
- package/src/tool/mcp-sse-transport.ts +15 -2
- package/src/tool/mcp-transport.ts +16 -0
- package/src/tool/oauth.ts +24 -3
- package/src/util/oauth-util.ts +13 -0
package/dist/index.mjs
CHANGED
|
@@ -438,6 +438,13 @@ function resourceUrlFromServerUrl(url) {
|
|
|
438
438
|
resourceURL.hash = "";
|
|
439
439
|
return resourceURL;
|
|
440
440
|
}
|
|
441
|
+
function resourceUrlStripSlash(resource) {
|
|
442
|
+
const href = resource.href;
|
|
443
|
+
if (resource.pathname === "/" && href.endsWith("/")) {
|
|
444
|
+
return href.slice(0, -1);
|
|
445
|
+
}
|
|
446
|
+
return href;
|
|
447
|
+
}
|
|
441
448
|
function checkResourceAllowed({
|
|
442
449
|
requestedResource,
|
|
443
450
|
configuredResource
|
|
@@ -676,7 +683,10 @@ async function startAuthorization(authorizationServerUrl, {
|
|
|
676
683
|
authorizationUrl.searchParams.append("prompt", "consent");
|
|
677
684
|
}
|
|
678
685
|
if (resource) {
|
|
679
|
-
authorizationUrl.searchParams.set(
|
|
686
|
+
authorizationUrl.searchParams.set(
|
|
687
|
+
"resource",
|
|
688
|
+
resourceUrlStripSlash(resource)
|
|
689
|
+
);
|
|
680
690
|
}
|
|
681
691
|
return { authorizationUrl, codeVerifier };
|
|
682
692
|
}
|
|
@@ -785,7 +795,7 @@ async function exchangeAuthorization(authorizationServerUrl, {
|
|
|
785
795
|
applyClientAuthentication(authMethod, clientInformation, headers, params);
|
|
786
796
|
}
|
|
787
797
|
if (resource) {
|
|
788
|
-
params.set("resource", resource
|
|
798
|
+
params.set("resource", resourceUrlStripSlash(resource));
|
|
789
799
|
}
|
|
790
800
|
const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
|
|
791
801
|
method: "POST",
|
|
@@ -837,7 +847,7 @@ async function refreshAuthorization(authorizationServerUrl, {
|
|
|
837
847
|
applyClientAuthentication(authMethod, clientInformation, headers, params);
|
|
838
848
|
}
|
|
839
849
|
if (resource) {
|
|
840
|
-
params.set("resource", resource
|
|
850
|
+
params.set("resource", resourceUrlStripSlash(resource));
|
|
841
851
|
}
|
|
842
852
|
const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
|
|
843
853
|
method: "POST",
|
|
@@ -919,6 +929,7 @@ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
|
919
929
|
async function authInternal(provider, {
|
|
920
930
|
serverUrl,
|
|
921
931
|
authorizationCode,
|
|
932
|
+
callbackState,
|
|
922
933
|
scope,
|
|
923
934
|
resourceMetadataUrl,
|
|
924
935
|
fetchFn
|
|
@@ -971,6 +982,14 @@ async function authInternal(provider, {
|
|
|
971
982
|
clientInformation = fullInformation;
|
|
972
983
|
}
|
|
973
984
|
if (authorizationCode !== void 0) {
|
|
985
|
+
if (provider.storedState) {
|
|
986
|
+
const expectedState = await provider.storedState();
|
|
987
|
+
if (expectedState !== void 0 && expectedState !== callbackState) {
|
|
988
|
+
throw new Error(
|
|
989
|
+
"OAuth state parameter mismatch - possible CSRF attack"
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
974
993
|
const codeVerifier2 = await provider.codeVerifier();
|
|
975
994
|
const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
|
|
976
995
|
metadata,
|
|
@@ -1009,6 +1028,9 @@ async function authInternal(provider, {
|
|
|
1009
1028
|
}
|
|
1010
1029
|
}
|
|
1011
1030
|
const state = provider.state ? await provider.state() : void 0;
|
|
1031
|
+
if (state && provider.saveState) {
|
|
1032
|
+
await provider.saveState(state);
|
|
1033
|
+
}
|
|
1012
1034
|
const { authorizationUrl, codeVerifier } = await startAuthorization(
|
|
1013
1035
|
authorizationServerUrl,
|
|
1014
1036
|
{
|
|
@@ -1030,12 +1052,16 @@ var SseMCPTransport = class {
|
|
|
1030
1052
|
constructor({
|
|
1031
1053
|
url,
|
|
1032
1054
|
headers,
|
|
1033
|
-
authProvider
|
|
1055
|
+
authProvider,
|
|
1056
|
+
redirect = "error",
|
|
1057
|
+
fetch: fetchFn
|
|
1034
1058
|
}) {
|
|
1035
1059
|
this.connected = false;
|
|
1036
1060
|
this.url = new URL(url);
|
|
1037
1061
|
this.headers = headers;
|
|
1038
1062
|
this.authProvider = authProvider;
|
|
1063
|
+
this.redirectMode = redirect;
|
|
1064
|
+
this.fetchFn = fetchFn != null ? fetchFn : globalThis.fetch;
|
|
1039
1065
|
}
|
|
1040
1066
|
async commonHeaders(base) {
|
|
1041
1067
|
const headers = {
|
|
@@ -1067,16 +1093,18 @@ var SseMCPTransport = class {
|
|
|
1067
1093
|
const headers = await this.commonHeaders({
|
|
1068
1094
|
Accept: "text/event-stream"
|
|
1069
1095
|
});
|
|
1070
|
-
const response = await
|
|
1096
|
+
const response = await this.fetchFn(this.url.href, {
|
|
1071
1097
|
headers,
|
|
1072
|
-
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
|
|
1098
|
+
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
|
|
1099
|
+
redirect: this.redirectMode
|
|
1073
1100
|
});
|
|
1074
1101
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1075
1102
|
this.resourceMetadataUrl = extractResourceMetadataUrl(response);
|
|
1076
1103
|
try {
|
|
1077
1104
|
const result = await auth(this.authProvider, {
|
|
1078
1105
|
serverUrl: this.url,
|
|
1079
|
-
resourceMetadataUrl: this.resourceMetadataUrl
|
|
1106
|
+
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1107
|
+
fetchFn: this.fetchFn
|
|
1080
1108
|
});
|
|
1081
1109
|
if (result !== "AUTHORIZED") {
|
|
1082
1110
|
const error = new UnauthorizedError();
|
|
@@ -1188,15 +1216,17 @@ var SseMCPTransport = class {
|
|
|
1188
1216
|
method: "POST",
|
|
1189
1217
|
headers,
|
|
1190
1218
|
body: JSON.stringify(message),
|
|
1191
|
-
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
|
|
1219
|
+
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
|
|
1220
|
+
redirect: this.redirectMode
|
|
1192
1221
|
};
|
|
1193
|
-
const response = await
|
|
1222
|
+
const response = await this.fetchFn(endpoint.href, init);
|
|
1194
1223
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1195
1224
|
this.resourceMetadataUrl = extractResourceMetadataUrl(response);
|
|
1196
1225
|
try {
|
|
1197
1226
|
const result = await auth(this.authProvider, {
|
|
1198
1227
|
serverUrl: this.url,
|
|
1199
|
-
resourceMetadataUrl: this.resourceMetadataUrl
|
|
1228
|
+
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1229
|
+
fetchFn: this.fetchFn
|
|
1200
1230
|
});
|
|
1201
1231
|
if (result !== "AUTHORIZED") {
|
|
1202
1232
|
const error = new UnauthorizedError();
|
|
@@ -1236,7 +1266,9 @@ var HttpMCPTransport = class {
|
|
|
1236
1266
|
constructor({
|
|
1237
1267
|
url,
|
|
1238
1268
|
headers,
|
|
1239
|
-
authProvider
|
|
1269
|
+
authProvider,
|
|
1270
|
+
redirect = "error",
|
|
1271
|
+
fetch: fetchFn
|
|
1240
1272
|
}) {
|
|
1241
1273
|
this.inboundReconnectAttempts = 0;
|
|
1242
1274
|
this.reconnectionOptions = {
|
|
@@ -1248,6 +1280,8 @@ var HttpMCPTransport = class {
|
|
|
1248
1280
|
this.url = new URL(url);
|
|
1249
1281
|
this.headers = headers;
|
|
1250
1282
|
this.authProvider = authProvider;
|
|
1283
|
+
this.redirectMode = redirect;
|
|
1284
|
+
this.fetchFn = fetchFn != null ? fetchFn : globalThis.fetch;
|
|
1251
1285
|
}
|
|
1252
1286
|
async commonHeaders(base) {
|
|
1253
1287
|
const headers = {
|
|
@@ -1285,10 +1319,11 @@ var HttpMCPTransport = class {
|
|
|
1285
1319
|
try {
|
|
1286
1320
|
if (this.sessionId && this.abortController && !this.abortController.signal.aborted) {
|
|
1287
1321
|
const headers = await this.commonHeaders({});
|
|
1288
|
-
await
|
|
1322
|
+
await this.fetchFn(this.url.href, {
|
|
1289
1323
|
method: "DELETE",
|
|
1290
1324
|
headers,
|
|
1291
|
-
signal: this.abortController.signal
|
|
1325
|
+
signal: this.abortController.signal,
|
|
1326
|
+
redirect: this.redirectMode
|
|
1292
1327
|
}).catch(() => void 0);
|
|
1293
1328
|
}
|
|
1294
1329
|
} catch (e) {
|
|
@@ -1308,9 +1343,10 @@ var HttpMCPTransport = class {
|
|
|
1308
1343
|
method: "POST",
|
|
1309
1344
|
headers,
|
|
1310
1345
|
body: JSON.stringify(message),
|
|
1311
|
-
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
|
|
1346
|
+
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
|
|
1347
|
+
redirect: this.redirectMode
|
|
1312
1348
|
};
|
|
1313
|
-
const response = await
|
|
1349
|
+
const response = await this.fetchFn(this.url.href, init);
|
|
1314
1350
|
const sessionId = response.headers.get("mcp-session-id");
|
|
1315
1351
|
if (sessionId) {
|
|
1316
1352
|
this.sessionId = sessionId;
|
|
@@ -1320,7 +1356,8 @@ var HttpMCPTransport = class {
|
|
|
1320
1356
|
try {
|
|
1321
1357
|
const result = await auth(this.authProvider, {
|
|
1322
1358
|
serverUrl: this.url,
|
|
1323
|
-
resourceMetadataUrl: this.resourceMetadataUrl
|
|
1359
|
+
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1360
|
+
fetchFn: this.fetchFn
|
|
1324
1361
|
});
|
|
1325
1362
|
if (result !== "AUTHORIZED") {
|
|
1326
1363
|
const error2 = new UnauthorizedError();
|
|
@@ -1454,10 +1491,11 @@ var HttpMCPTransport = class {
|
|
|
1454
1491
|
if (resumeToken) {
|
|
1455
1492
|
headers["last-event-id"] = resumeToken;
|
|
1456
1493
|
}
|
|
1457
|
-
const response = await
|
|
1494
|
+
const response = await this.fetchFn(this.url.href, {
|
|
1458
1495
|
method: "GET",
|
|
1459
1496
|
headers,
|
|
1460
|
-
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
|
|
1497
|
+
signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
|
|
1498
|
+
redirect: this.redirectMode
|
|
1461
1499
|
});
|
|
1462
1500
|
const sessionId = response.headers.get("mcp-session-id");
|
|
1463
1501
|
if (sessionId) {
|
|
@@ -1468,7 +1506,8 @@ var HttpMCPTransport = class {
|
|
|
1468
1506
|
try {
|
|
1469
1507
|
const result = await auth(this.authProvider, {
|
|
1470
1508
|
serverUrl: this.url,
|
|
1471
|
-
resourceMetadataUrl: this.resourceMetadataUrl
|
|
1509
|
+
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1510
|
+
fetchFn: this.fetchFn
|
|
1472
1511
|
});
|
|
1473
1512
|
if (result !== "AUTHORIZED") {
|
|
1474
1513
|
const error = new UnauthorizedError();
|
|
@@ -1903,6 +1942,9 @@ var DefaultMCPClient = class {
|
|
|
1903
1942
|
var _a4;
|
|
1904
1943
|
(_a4 = options == null ? void 0 : options.abortSignal) == null ? void 0 : _a4.throwIfAborted();
|
|
1905
1944
|
const result = await self.callTool({ name: name3, args, options });
|
|
1945
|
+
if (result.isError) {
|
|
1946
|
+
return result;
|
|
1947
|
+
}
|
|
1906
1948
|
if (outputSchema != null) {
|
|
1907
1949
|
return self.extractStructuredContent(result, outputSchema, name3);
|
|
1908
1950
|
}
|