@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/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("resource", resource.href);
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.href);
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.href);
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 fetch(this.url.href, {
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 fetch(endpoint, init);
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 fetch(this.url, {
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 fetch(this.url, init);
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 fetch(this.url.href, {
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
  }