@ai-sdk/mcp 1.0.70 → 1.0.72
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 +14 -0
- package/dist/index.js +68 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +68 -41
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-stdio/index.js.map +1 -1
- package/dist/mcp-stdio/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/error/mcp-client-error.ts +1 -1
- package/src/tool/mcp-http-transport.ts +20 -6
- package/src/tool/mcp-sse-transport.ts +21 -20
- package/src/tool/oauth.ts +52 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @ai-sdk/mcp
|
|
2
2
|
|
|
3
|
+
## 1.0.72
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0075ed5: fix(mcp): reject SSE requests when POST responses are unsuccessful
|
|
8
|
+
|
|
9
|
+
## 1.0.71
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- b0e77c0: Select MCP OAuth authorization scopes from `WWW-Authenticate` challenges or Protected Resource Metadata.
|
|
14
|
+
- Updated dependencies [31205a4]
|
|
15
|
+
- @ai-sdk/provider-utils@4.0.46
|
|
16
|
+
|
|
3
17
|
## 1.0.70
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -661,26 +661,41 @@ function assertAuthorizationServerInformationMatches({
|
|
|
661
661
|
});
|
|
662
662
|
}
|
|
663
663
|
}
|
|
664
|
-
function
|
|
665
|
-
var _a3;
|
|
664
|
+
function extractWWWAuthenticateParams(response) {
|
|
665
|
+
var _a3, _b3;
|
|
666
666
|
const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
|
|
667
667
|
if (!header) {
|
|
668
|
-
return
|
|
668
|
+
return {};
|
|
669
669
|
}
|
|
670
670
|
const [type, scheme] = header.split(" ");
|
|
671
|
-
if (type.toLowerCase() !== "bearer" || !scheme) {
|
|
672
|
-
return
|
|
673
|
-
}
|
|
674
|
-
const regex = /resource_metadata="([^"]*)"/;
|
|
675
|
-
const match = header.match(regex);
|
|
676
|
-
if (!match) {
|
|
677
|
-
return void 0;
|
|
671
|
+
if (type.replace(/,$/, "").toLowerCase() !== "bearer" || !scheme) {
|
|
672
|
+
return {};
|
|
678
673
|
}
|
|
674
|
+
const resourceMetadataMatch = header.match(
|
|
675
|
+
/(?:^|[,\s])resource_metadata="([^"]*)"/i
|
|
676
|
+
);
|
|
677
|
+
const scope = (_b3 = header.match(/(?:^|[,\s])scope="([^"]*)"/i)) == null ? void 0 : _b3[1];
|
|
678
|
+
let resourceMetadataUrl;
|
|
679
679
|
try {
|
|
680
|
-
|
|
680
|
+
resourceMetadataUrl = resourceMetadataMatch ? new URL(resourceMetadataMatch[1]) : void 0;
|
|
681
681
|
} catch (e) {
|
|
682
|
-
return void 0;
|
|
683
682
|
}
|
|
683
|
+
return { resourceMetadataUrl, scope };
|
|
684
|
+
}
|
|
685
|
+
function selectScope({
|
|
686
|
+
scope,
|
|
687
|
+
resourceMetadata,
|
|
688
|
+
clientMetadata
|
|
689
|
+
}) {
|
|
690
|
+
var _a3;
|
|
691
|
+
if (scope) {
|
|
692
|
+
return scope;
|
|
693
|
+
}
|
|
694
|
+
const resourceScopes = (_a3 = resourceMetadata == null ? void 0 : resourceMetadata.scopes_supported) == null ? void 0 : _a3.join(" ");
|
|
695
|
+
if (resourceScopes) {
|
|
696
|
+
return resourceScopes;
|
|
697
|
+
}
|
|
698
|
+
return clientMetadata.scope;
|
|
684
699
|
}
|
|
685
700
|
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
686
701
|
if (pathname.endsWith("/")) {
|
|
@@ -1309,7 +1324,11 @@ async function authInternal(provider, {
|
|
|
1309
1324
|
clientInformation,
|
|
1310
1325
|
state,
|
|
1311
1326
|
redirectUrl: provider.redirectUrl,
|
|
1312
|
-
scope:
|
|
1327
|
+
scope: selectScope({
|
|
1328
|
+
scope,
|
|
1329
|
+
resourceMetadata,
|
|
1330
|
+
clientMetadata: provider.clientMetadata
|
|
1331
|
+
}),
|
|
1313
1332
|
resource
|
|
1314
1333
|
}
|
|
1315
1334
|
);
|
|
@@ -1387,11 +1406,13 @@ var SseMCPTransport = class {
|
|
|
1387
1406
|
redirect: this.redirectMode
|
|
1388
1407
|
});
|
|
1389
1408
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1390
|
-
|
|
1409
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
1410
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
1391
1411
|
try {
|
|
1392
1412
|
const result = await auth(this.authProvider, {
|
|
1393
1413
|
serverUrl: this.url,
|
|
1394
1414
|
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1415
|
+
scope,
|
|
1395
1416
|
fetchFn: this.fetchFn
|
|
1396
1417
|
});
|
|
1397
1418
|
if (result !== "AUTHORIZED") {
|
|
@@ -1506,7 +1527,7 @@ var SseMCPTransport = class {
|
|
|
1506
1527
|
const transportSignal = (_b3 = this.abortController) == null ? void 0 : _b3.signal;
|
|
1507
1528
|
const requestSignal = (options == null ? void 0 : options.signal) == null ? transportSignal : transportSignal == null ? options.signal : AbortSignal.any([transportSignal, options.signal]);
|
|
1508
1529
|
const attempt = async (triedAuth = false) => {
|
|
1509
|
-
var _a4, _b4
|
|
1530
|
+
var _a4, _b4;
|
|
1510
1531
|
try {
|
|
1511
1532
|
const headers = await this.commonHeaders({
|
|
1512
1533
|
"Content-Type": "application/json"
|
|
@@ -1520,38 +1541,35 @@ var SseMCPTransport = class {
|
|
|
1520
1541
|
};
|
|
1521
1542
|
const response = await this.fetchFn(endpoint.href, init);
|
|
1522
1543
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
return;
|
|
1534
|
-
}
|
|
1535
|
-
} catch (error) {
|
|
1536
|
-
(_b4 = this.onerror) == null ? void 0 : _b4.call(this, error);
|
|
1537
|
-
return;
|
|
1544
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
1545
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
1546
|
+
const result = await auth(this.authProvider, {
|
|
1547
|
+
serverUrl: this.url,
|
|
1548
|
+
resourceMetadataUrl: this.resourceMetadataUrl,
|
|
1549
|
+
scope,
|
|
1550
|
+
fetchFn: this.fetchFn
|
|
1551
|
+
});
|
|
1552
|
+
if (result !== "AUTHORIZED") {
|
|
1553
|
+
throw new UnauthorizedError();
|
|
1538
1554
|
}
|
|
1539
1555
|
return attempt(true);
|
|
1540
1556
|
}
|
|
1541
1557
|
if (!response.ok) {
|
|
1542
1558
|
const text = await response.text().catch(() => null);
|
|
1543
1559
|
const error = new MCPClientError({
|
|
1544
|
-
message: `MCP SSE Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}
|
|
1560
|
+
message: `MCP SSE Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}`,
|
|
1561
|
+
statusCode: response.status,
|
|
1562
|
+
url: endpoint.href,
|
|
1563
|
+
responseBody: text != null ? text : void 0
|
|
1545
1564
|
});
|
|
1546
|
-
|
|
1547
|
-
return;
|
|
1565
|
+
throw error;
|
|
1548
1566
|
}
|
|
1549
1567
|
} catch (error) {
|
|
1550
|
-
if ((
|
|
1568
|
+
if ((_a4 = options == null ? void 0 : options.signal) == null ? void 0 : _a4.aborted) {
|
|
1551
1569
|
throw error;
|
|
1552
1570
|
}
|
|
1553
|
-
(
|
|
1554
|
-
|
|
1571
|
+
(_b4 = this.onerror) == null ? void 0 : _b4.call(this, error);
|
|
1572
|
+
throw error;
|
|
1555
1573
|
}
|
|
1556
1574
|
};
|
|
1557
1575
|
await attempt();
|
|
@@ -1612,7 +1630,7 @@ var HttpMCPTransport = class {
|
|
|
1612
1630
|
/**
|
|
1613
1631
|
* Runs a single OAuth recovery flow for concurrent 401 responses.
|
|
1614
1632
|
*/
|
|
1615
|
-
authorizeOnce(resourceMetadataUrl) {
|
|
1633
|
+
authorizeOnce(resourceMetadataUrl, scope) {
|
|
1616
1634
|
if (!this.authProvider) {
|
|
1617
1635
|
return Promise.resolve("REDIRECT");
|
|
1618
1636
|
}
|
|
@@ -1620,6 +1638,7 @@ var HttpMCPTransport = class {
|
|
|
1620
1638
|
this.authPromise = auth(this.authProvider, {
|
|
1621
1639
|
serverUrl: this.url,
|
|
1622
1640
|
resourceMetadataUrl,
|
|
1641
|
+
scope,
|
|
1623
1642
|
fetchFn: this.fetchFn
|
|
1624
1643
|
}).finally(() => {
|
|
1625
1644
|
this.authPromise = void 0;
|
|
@@ -1681,9 +1700,13 @@ var HttpMCPTransport = class {
|
|
|
1681
1700
|
this.sessionId = sessionId;
|
|
1682
1701
|
}
|
|
1683
1702
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1684
|
-
|
|
1703
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
1704
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
1685
1705
|
try {
|
|
1686
|
-
const result = await this.authorizeOnce(
|
|
1706
|
+
const result = await this.authorizeOnce(
|
|
1707
|
+
this.resourceMetadataUrl,
|
|
1708
|
+
scope
|
|
1709
|
+
);
|
|
1687
1710
|
if (result !== "AUTHORIZED") {
|
|
1688
1711
|
const error2 = new UnauthorizedError();
|
|
1689
1712
|
throw error2;
|
|
@@ -1854,9 +1877,13 @@ var HttpMCPTransport = class {
|
|
|
1854
1877
|
this.sessionId = sessionId;
|
|
1855
1878
|
}
|
|
1856
1879
|
if (response.status === 401 && this.authProvider && !triedAuth) {
|
|
1857
|
-
|
|
1880
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
|
|
1881
|
+
this.resourceMetadataUrl = resourceMetadataUrl;
|
|
1858
1882
|
try {
|
|
1859
|
-
const result = await this.authorizeOnce(
|
|
1883
|
+
const result = await this.authorizeOnce(
|
|
1884
|
+
this.resourceMetadataUrl,
|
|
1885
|
+
scope
|
|
1886
|
+
);
|
|
1860
1887
|
if (result !== "AUTHORIZED") {
|
|
1861
1888
|
const error = new UnauthorizedError();
|
|
1862
1889
|
(_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);
|