@ai-sdk/mcp 2.0.31 → 2.0.32

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,11 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 2.0.32
4
+
5
+ ### Patch Changes
6
+
7
+ - 1011e33: Select MCP OAuth authorization scopes from `WWW-Authenticate` challenges or Protected Resource Metadata.
8
+
3
9
  ## 2.0.31
4
10
 
5
11
  ### Patch Changes
package/dist/index.js CHANGED
@@ -631,26 +631,41 @@ function assertAuthorizationServerInformationMatches({
631
631
  });
632
632
  }
633
633
  }
634
- function extractResourceMetadataUrl(response) {
635
- var _a3;
634
+ function extractWWWAuthenticateParams(response) {
635
+ var _a3, _b3;
636
636
  const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
637
637
  if (!header) {
638
- return void 0;
638
+ return {};
639
639
  }
640
640
  const [type, scheme] = header.split(" ");
641
641
  if (type.toLowerCase() !== "bearer" || !scheme) {
642
- return void 0;
643
- }
644
- const regex = /resource_metadata="([^"]*)"/;
645
- const match = header.match(regex);
646
- if (!match) {
647
- return void 0;
642
+ return {};
648
643
  }
644
+ const resourceMetadataMatch = header.match(
645
+ /(?:^|[,\s])resource_metadata="([^"]*)"/i
646
+ );
647
+ const scope = (_b3 = header.match(/(?:^|[,\s])scope="([^"]*)"/i)) == null ? void 0 : _b3[1];
648
+ let resourceMetadataUrl;
649
649
  try {
650
- return new URL(match[1]);
650
+ resourceMetadataUrl = resourceMetadataMatch ? new URL(resourceMetadataMatch[1]) : void 0;
651
651
  } catch (e) {
652
- return void 0;
653
652
  }
653
+ return { resourceMetadataUrl, scope };
654
+ }
655
+ function selectScope({
656
+ scope,
657
+ resourceMetadata,
658
+ clientMetadata
659
+ }) {
660
+ var _a3;
661
+ if (scope) {
662
+ return scope;
663
+ }
664
+ const resourceScopes = (_a3 = resourceMetadata == null ? void 0 : resourceMetadata.scopes_supported) == null ? void 0 : _a3.join(" ");
665
+ if (resourceScopes) {
666
+ return resourceScopes;
667
+ }
668
+ return clientMetadata.scope;
654
669
  }
655
670
  function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
656
671
  if (pathname.endsWith("/")) {
@@ -1279,7 +1294,11 @@ async function authInternal(provider, {
1279
1294
  clientInformation,
1280
1295
  state,
1281
1296
  redirectUrl: provider.redirectUrl,
1282
- scope: scope || provider.clientMetadata.scope,
1297
+ scope: selectScope({
1298
+ scope,
1299
+ resourceMetadata,
1300
+ clientMetadata: provider.clientMetadata
1301
+ }),
1283
1302
  resource
1284
1303
  }
1285
1304
  );
@@ -1357,11 +1376,13 @@ var SseMCPTransport = class {
1357
1376
  redirect: this.redirectMode
1358
1377
  });
1359
1378
  if (response.status === 401 && this.authProvider && !triedAuth) {
1360
- this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1379
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
1380
+ this.resourceMetadataUrl = resourceMetadataUrl;
1361
1381
  try {
1362
1382
  const result = await auth(this.authProvider, {
1363
1383
  serverUrl: this.url,
1364
1384
  resourceMetadataUrl: this.resourceMetadataUrl,
1385
+ scope,
1365
1386
  fetchFn: this.fetchFn
1366
1387
  });
1367
1388
  if (result !== "AUTHORIZED") {
@@ -1490,11 +1511,13 @@ var SseMCPTransport = class {
1490
1511
  };
1491
1512
  const response = await this.fetchFn(endpoint.href, init);
1492
1513
  if (response.status === 401 && this.authProvider && !triedAuth) {
1493
- this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1514
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
1515
+ this.resourceMetadataUrl = resourceMetadataUrl;
1494
1516
  try {
1495
1517
  const result = await auth(this.authProvider, {
1496
1518
  serverUrl: this.url,
1497
1519
  resourceMetadataUrl: this.resourceMetadataUrl,
1520
+ scope,
1498
1521
  fetchFn: this.fetchFn
1499
1522
  });
1500
1523
  if (result !== "AUTHORIZED") {
@@ -1620,7 +1643,7 @@ var HttpMCPTransport = class {
1620
1643
  /**
1621
1644
  * Runs a single OAuth recovery flow for concurrent 401 responses.
1622
1645
  */
1623
- authorizeOnce(resourceMetadataUrl) {
1646
+ authorizeOnce(resourceMetadataUrl, scope) {
1624
1647
  if (!this.authProvider) {
1625
1648
  return Promise.resolve("REDIRECT");
1626
1649
  }
@@ -1628,6 +1651,7 @@ var HttpMCPTransport = class {
1628
1651
  this.authPromise = auth(this.authProvider, {
1629
1652
  serverUrl: this.url,
1630
1653
  resourceMetadataUrl,
1654
+ scope,
1631
1655
  fetchFn: this.fetchFn
1632
1656
  }).finally(() => {
1633
1657
  this.authPromise = void 0;
@@ -1691,9 +1715,13 @@ var HttpMCPTransport = class {
1691
1715
  const response = await this.fetchFn(this.url.href, init);
1692
1716
  this.applySessionIdFromResponse(response);
1693
1717
  if (response.status === 401 && this.authProvider && !triedAuth) {
1694
- this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1718
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
1719
+ this.resourceMetadataUrl = resourceMetadataUrl;
1695
1720
  try {
1696
- const result = await this.authorizeOnce(this.resourceMetadataUrl);
1721
+ const result = await this.authorizeOnce(
1722
+ this.resourceMetadataUrl,
1723
+ scope
1724
+ );
1697
1725
  if (result !== "AUTHORIZED") {
1698
1726
  const error2 = new UnauthorizedError();
1699
1727
  throw error2;
@@ -1869,9 +1897,13 @@ var HttpMCPTransport = class {
1869
1897
  });
1870
1898
  this.applySessionIdFromResponse(response);
1871
1899
  if (response.status === 401 && this.authProvider && !triedAuth) {
1872
- this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1900
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
1901
+ this.resourceMetadataUrl = resourceMetadataUrl;
1873
1902
  try {
1874
- const result = await this.authorizeOnce(this.resourceMetadataUrl);
1903
+ const result = await this.authorizeOnce(
1904
+ this.resourceMetadataUrl,
1905
+ scope
1906
+ );
1875
1907
  if (result !== "AUTHORIZED") {
1876
1908
  const error = new UnauthorizedError();
1877
1909
  (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);