@ai-sdk/mcp 2.0.79 → 2.0.80
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 +10 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -7
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/tool/oauth.ts +64 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/mcp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.80",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ai-sdk/provider": "4.0.
|
|
35
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
34
|
+
"@ai-sdk/provider": "4.0.31",
|
|
35
|
+
"@ai-sdk/provider-utils": "5.0.64",
|
|
36
36
|
"cross-spawn": "^7.0.6",
|
|
37
37
|
"pkce-challenge": "^5.0.1"
|
|
38
38
|
},
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@types/cross-spawn": "^6.0.6",
|
|
42
42
|
"@types/node": "22.19.19",
|
|
43
43
|
"@vercel/ai-tsconfig": "0.0.0",
|
|
44
|
+
"@vercel/ai-tsdown-config": "0.0.0",
|
|
44
45
|
"tsdown": "^0.23.0",
|
|
45
46
|
"typescript": "6.0.3",
|
|
46
47
|
"vitest": "^4.1.11",
|
package/src/tool/oauth.ts
CHANGED
|
@@ -94,6 +94,11 @@ export interface OAuthClientProvider {
|
|
|
94
94
|
): void | Promise<void>;
|
|
95
95
|
get redirectUrl(): string | URL;
|
|
96
96
|
get clientMetadata(): OAuthClientMetadata;
|
|
97
|
+
/**
|
|
98
|
+
* Returns client credentials. Pre-registered confidential clients must specify
|
|
99
|
+
* their authorization server's `issuer` or provide stored authorization server
|
|
100
|
+
* information. `validateAuthorizationServerURL` does not replace this binding.
|
|
101
|
+
*/
|
|
97
102
|
clientInformation():
|
|
98
103
|
| OAuthClientInformation
|
|
99
104
|
| undefined
|
|
@@ -121,6 +126,7 @@ export interface OAuthClientProvider {
|
|
|
121
126
|
/**
|
|
122
127
|
* Validates an authorization server URL discovered from MCP protected resource
|
|
123
128
|
* metadata before the client fetches its OAuth metadata.
|
|
129
|
+
* This additional restriction does not bind client credentials to that server.
|
|
124
130
|
*/
|
|
125
131
|
validateAuthorizationServerURL?(
|
|
126
132
|
serverUrl: string | URL,
|
|
@@ -1299,11 +1305,20 @@ export async function auth(
|
|
|
1299
1305
|
await provider.invalidateCredentials?.('all');
|
|
1300
1306
|
return await authInternal(provider, options);
|
|
1301
1307
|
} else if (error instanceof InvalidGrantError && refreshAttempt.tokens) {
|
|
1308
|
+
// Keep the binding validated before the refresh, even when deleting the
|
|
1309
|
+
// rejected tokens removes the provider's only copy of that binding.
|
|
1310
|
+
const retryAuthorizationServerInformation =
|
|
1311
|
+
getAuthorizationServerInformationFromCredentials(refreshAttempt.tokens);
|
|
1302
1312
|
// Only invalidate the tokens used by a failed refresh.
|
|
1303
1313
|
await provider.invalidateCredentials?.('tokens', {
|
|
1304
1314
|
tokens: refreshAttempt.tokens,
|
|
1305
1315
|
});
|
|
1306
|
-
return await authInternal(
|
|
1316
|
+
return await authInternal(
|
|
1317
|
+
provider,
|
|
1318
|
+
options,
|
|
1319
|
+
undefined,
|
|
1320
|
+
retryAuthorizationServerInformation,
|
|
1321
|
+
);
|
|
1307
1322
|
}
|
|
1308
1323
|
|
|
1309
1324
|
throw error;
|
|
@@ -1361,6 +1376,7 @@ async function authInternal(
|
|
|
1361
1376
|
fetchFn?: FetchFunction;
|
|
1362
1377
|
},
|
|
1363
1378
|
refreshAttempt?: { tokens?: OAuthTokens },
|
|
1379
|
+
retryAuthorizationServerInformation?: OAuthAuthorizationServerInformation,
|
|
1364
1380
|
): Promise<AuthResult> {
|
|
1365
1381
|
let resourceMetadata: OAuthProtectedResourceMetadata | undefined;
|
|
1366
1382
|
let authorizationServerUrl: string | URL | undefined;
|
|
@@ -1451,6 +1467,12 @@ async function authInternal(
|
|
|
1451
1467
|
);
|
|
1452
1468
|
const currentAuthorizationServerInformation =
|
|
1453
1469
|
createAuthorizationServerInformation(authorizationServerUrl, metadata);
|
|
1470
|
+
if (retryAuthorizationServerInformation) {
|
|
1471
|
+
assertAuthorizationServerInformationMatches({
|
|
1472
|
+
storedAuthorizationServerInformation: retryAuthorizationServerInformation,
|
|
1473
|
+
currentAuthorizationServerInformation,
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1454
1476
|
const clientMetadata = provider.clientMetadata;
|
|
1455
1477
|
const selectedScope = selectScope({
|
|
1456
1478
|
scope,
|
|
@@ -1462,19 +1484,58 @@ async function authInternal(
|
|
|
1462
1484
|
if (authorizationCode === undefined) {
|
|
1463
1485
|
clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1464
1486
|
}
|
|
1465
|
-
|
|
1487
|
+
const tokens =
|
|
1488
|
+
authorizationCode === undefined ? await provider.tokens() : undefined;
|
|
1489
|
+
if (clientInformation) {
|
|
1490
|
+
// A flow pin must never override the issuer attached to the credentials.
|
|
1491
|
+
if (
|
|
1492
|
+
clientInformation.issuer != null &&
|
|
1493
|
+
clientInformation.issuer !== currentAuthorizationServerInformation.issuer
|
|
1494
|
+
) {
|
|
1495
|
+
throw new AuthorizationServerMismatchError({
|
|
1496
|
+
message:
|
|
1497
|
+
'OAuth authorization server does not match the issuer of the client credentials',
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
const clientAuthorizationServerInformation =
|
|
1502
|
+
getAuthorizationServerInformationFromCredentials(clientInformation);
|
|
1503
|
+
if (clientAuthorizationServerInformation) {
|
|
1504
|
+
assertAuthorizationServerInformationMatches({
|
|
1505
|
+
storedAuthorizationServerInformation:
|
|
1506
|
+
clientAuthorizationServerInformation,
|
|
1507
|
+
currentAuthorizationServerInformation,
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1466
1511
|
const storedAuthorizationServerInformation =
|
|
1467
1512
|
callbackAuthorizationServerInformation ??
|
|
1468
1513
|
(await getStoredAuthorizationServerInformation({
|
|
1469
1514
|
provider,
|
|
1470
1515
|
clientInformation,
|
|
1471
|
-
|
|
1516
|
+
tokens,
|
|
1517
|
+
})) ??
|
|
1518
|
+
retryAuthorizationServerInformation;
|
|
1472
1519
|
if (storedAuthorizationServerInformation) {
|
|
1473
1520
|
assertAuthorizationServerInformationMatches({
|
|
1474
1521
|
storedAuthorizationServerInformation,
|
|
1475
1522
|
currentAuthorizationServerInformation,
|
|
1476
1523
|
});
|
|
1477
1524
|
}
|
|
1525
|
+
|
|
1526
|
+
// Do not turn an MCP server's choice of AS into a trust binding for an
|
|
1527
|
+
// existing secret. Dynamic registration below binds newly issued credentials.
|
|
1528
|
+
if (
|
|
1529
|
+
(clientInformation.client_secret != null ||
|
|
1530
|
+
provider.addClientAuthentication) &&
|
|
1531
|
+
clientInformation.issuer == null &&
|
|
1532
|
+
!storedAuthorizationServerInformation
|
|
1533
|
+
) {
|
|
1534
|
+
throw new AuthorizationServerMismatchError({
|
|
1535
|
+
message:
|
|
1536
|
+
'OAuth client credentials must be bound to an authorization server: configure their issuer or store authorization server information',
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1478
1539
|
}
|
|
1479
1540
|
|
|
1480
1541
|
if (!clientInformation) {
|
|
@@ -1562,8 +1623,6 @@ async function authInternal(
|
|
|
1562
1623
|
return 'AUTHORIZED';
|
|
1563
1624
|
}
|
|
1564
1625
|
|
|
1565
|
-
const tokens = await provider.tokens();
|
|
1566
|
-
|
|
1567
1626
|
/** Refresh only when stored credentials match the current AS pin */
|
|
1568
1627
|
if (tokens?.refresh_token) {
|
|
1569
1628
|
const storedAuthorizationServerInformation =
|