@ai-sdk/mcp 2.0.0-canary.59 → 2.0.0-canary.61
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 +13 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +181 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +4 -1
- package/src/tool/oauth-types.ts +18 -14
- package/src/tool/oauth.ts +251 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @ai-sdk/mcp
|
|
2
2
|
|
|
3
|
+
## 2.0.0-canary.61
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [bae5e2b]
|
|
8
|
+
- @ai-sdk/provider-utils@5.0.0-canary.47
|
|
9
|
+
|
|
10
|
+
## 2.0.0-canary.60
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- f0c6770: fix(mcp): prevent mcp oauth credential exfiltration during rediscovery
|
|
15
|
+
|
|
3
16
|
## 2.0.0-canary.59
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ declare const OAuthTokensSchema: z.ZodObject<{
|
|
|
77
77
|
expires_in: z.ZodOptional<z.ZodNumber>;
|
|
78
78
|
scope: z.ZodOptional<z.ZodString>;
|
|
79
79
|
refresh_token: z.ZodOptional<z.ZodString>;
|
|
80
|
+
authorization_server: z.ZodOptional<z.ZodString>;
|
|
81
|
+
token_endpoint: z.ZodOptional<z.ZodString>;
|
|
80
82
|
}, z.core.$strip>;
|
|
81
83
|
declare const OAuthMetadataSchema: z.ZodObject<{
|
|
82
84
|
issuer: z.ZodString;
|
|
@@ -116,6 +118,8 @@ declare const OAuthClientInformationSchema: z.ZodObject<{
|
|
|
116
118
|
client_secret: z.ZodOptional<z.ZodString>;
|
|
117
119
|
client_id_issued_at: z.ZodOptional<z.ZodNumber>;
|
|
118
120
|
client_secret_expires_at: z.ZodOptional<z.ZodNumber>;
|
|
121
|
+
authorization_server: z.ZodOptional<z.ZodString>;
|
|
122
|
+
token_endpoint: z.ZodOptional<z.ZodString>;
|
|
119
123
|
}, z.core.$strip>;
|
|
120
124
|
declare const OAuthClientMetadataSchema: z.ZodObject<{
|
|
121
125
|
redirect_uris: z.ZodArray<z.ZodString>;
|
|
@@ -143,6 +147,10 @@ type AuthorizationServerMetadata = OAuthMetadata | OpenIdProviderDiscoveryMetada
|
|
|
143
147
|
type OAuthClientMetadata = z.infer<typeof OAuthClientMetadataSchema>;
|
|
144
148
|
|
|
145
149
|
type AuthResult = 'AUTHORIZED' | 'REDIRECT';
|
|
150
|
+
interface OAuthAuthorizationServerInformation {
|
|
151
|
+
authorizationServerUrl: string;
|
|
152
|
+
tokenEndpoint: string;
|
|
153
|
+
}
|
|
146
154
|
interface OAuthClientProvider {
|
|
147
155
|
/**
|
|
148
156
|
* Returns current access token if present; undefined otherwise.
|
|
@@ -181,6 +189,8 @@ interface OAuthClientProvider {
|
|
|
181
189
|
get clientMetadata(): OAuthClientMetadata;
|
|
182
190
|
clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
|
|
183
191
|
saveClientInformation?(clientInformation: OAuthClientInformation): void | Promise<void>;
|
|
192
|
+
authorizationServerInformation?(): OAuthAuthorizationServerInformation | undefined | Promise<OAuthAuthorizationServerInformation | undefined>;
|
|
193
|
+
saveAuthorizationServerInformation?(authorizationServerInformation: OAuthAuthorizationServerInformation): void | Promise<void>;
|
|
184
194
|
state?(): string | Promise<string>;
|
|
185
195
|
saveState?(state: string): void | Promise<void>;
|
|
186
196
|
storedState?(): string | undefined | Promise<string | undefined>;
|
|
@@ -632,4 +642,4 @@ declare function readMCPAppResource({ client, uri, options, }: {
|
|
|
632
642
|
options?: RequestOptions;
|
|
633
643
|
}): Promise<MCPAppResource>;
|
|
634
644
|
|
|
635
|
-
export { type CallToolResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPAppResource, type MCPAppResourceCSP, type MCPAppResourceMeta, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, MCP_APP_MIME_TYPE, type McpProviderMetadata, type OAuthClientInformation, type OAuthClientMetadata, type OAuthClientProvider, type OAuthTokens, UnauthorizedError, auth, createMCPClient, type MCPClient as experimental_MCPClient, type ClientCapabilities as experimental_MCPClientCapabilities, type MCPClientConfig as experimental_MCPClientConfig, createMCPClient as experimental_createMCPClient, mcpAppClientCapabilities, readMCPAppResource, splitMCPAppTools };
|
|
645
|
+
export { type CallToolResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPAppResource, type MCPAppResourceCSP, type MCPAppResourceMeta, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, MCP_APP_MIME_TYPE, type McpProviderMetadata, type OAuthAuthorizationServerInformation, type OAuthClientInformation, type OAuthClientMetadata, type OAuthClientProvider, type OAuthTokens, UnauthorizedError, auth, createMCPClient, type MCPClient as experimental_MCPClient, type ClientCapabilities as experimental_MCPClientCapabilities, type MCPClientConfig as experimental_MCPClientConfig, createMCPClient as experimental_createMCPClient, mcpAppClientCapabilities, readMCPAppResource, splitMCPAppTools };
|
package/dist/index.js
CHANGED
|
@@ -312,15 +312,6 @@ import pkceChallenge from "pkce-challenge";
|
|
|
312
312
|
|
|
313
313
|
// src/tool/oauth-types.ts
|
|
314
314
|
import { z as z3 } from "zod/v4";
|
|
315
|
-
var OAuthTokensSchema = z3.object({
|
|
316
|
-
access_token: z3.string(),
|
|
317
|
-
id_token: z3.string().optional(),
|
|
318
|
-
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
319
|
-
token_type: z3.string(),
|
|
320
|
-
expires_in: z3.number().optional(),
|
|
321
|
-
scope: z3.string().optional(),
|
|
322
|
-
refresh_token: z3.string().optional()
|
|
323
|
-
}).strip();
|
|
324
315
|
var SafeUrlSchema = z3.string().url().superRefine((val, ctx) => {
|
|
325
316
|
if (!URL.canParse(val)) {
|
|
326
317
|
ctx.addIssue({
|
|
@@ -337,6 +328,17 @@ var SafeUrlSchema = z3.string().url().superRefine((val, ctx) => {
|
|
|
337
328
|
},
|
|
338
329
|
{ message: "URL cannot use javascript:, data:, or vbscript: scheme" }
|
|
339
330
|
);
|
|
331
|
+
var OAuthTokensSchema = z3.object({
|
|
332
|
+
access_token: z3.string(),
|
|
333
|
+
id_token: z3.string().optional(),
|
|
334
|
+
// Optional for OAuth 2.1, but necessary in OpenID Connect
|
|
335
|
+
token_type: z3.string(),
|
|
336
|
+
expires_in: z3.number().optional(),
|
|
337
|
+
scope: z3.string().optional(),
|
|
338
|
+
refresh_token: z3.string().optional(),
|
|
339
|
+
authorization_server: SafeUrlSchema.optional(),
|
|
340
|
+
token_endpoint: SafeUrlSchema.optional()
|
|
341
|
+
}).strip();
|
|
340
342
|
var OAuthProtectedResourceMetadataSchema = z3.object({
|
|
341
343
|
resource: z3.string().url(),
|
|
342
344
|
authorization_servers: z3.array(SafeUrlSchema).optional(),
|
|
@@ -389,7 +391,9 @@ var OAuthClientInformationSchema = z3.object({
|
|
|
389
391
|
client_id: z3.string(),
|
|
390
392
|
client_secret: z3.string().optional(),
|
|
391
393
|
client_id_issued_at: z3.number().optional(),
|
|
392
|
-
client_secret_expires_at: z3.number().optional()
|
|
394
|
+
client_secret_expires_at: z3.number().optional(),
|
|
395
|
+
authorization_server: SafeUrlSchema.optional(),
|
|
396
|
+
token_endpoint: SafeUrlSchema.optional()
|
|
393
397
|
}).strip();
|
|
394
398
|
var OAuthClientMetadataSchema = z3.object({
|
|
395
399
|
redirect_uris: z3.array(SafeUrlSchema),
|
|
@@ -494,6 +498,106 @@ var UnauthorizedError = class extends Error {
|
|
|
494
498
|
this.name = "UnauthorizedError";
|
|
495
499
|
}
|
|
496
500
|
};
|
|
501
|
+
function normalizeUrl(url) {
|
|
502
|
+
return new URL(url).href;
|
|
503
|
+
}
|
|
504
|
+
function createAuthorizationServerInformation(authorizationServerUrl, metadata) {
|
|
505
|
+
return {
|
|
506
|
+
authorizationServerUrl: normalizeUrl(authorizationServerUrl),
|
|
507
|
+
tokenEndpoint: normalizeUrl(
|
|
508
|
+
(metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl)
|
|
509
|
+
)
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function addAuthorizationServerInformationToTokens(tokens, authorizationServerInformation) {
|
|
513
|
+
return {
|
|
514
|
+
...tokens,
|
|
515
|
+
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
516
|
+
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function addAuthorizationServerInformationToClientInformation(clientInformation, authorizationServerInformation) {
|
|
520
|
+
return {
|
|
521
|
+
...clientInformation,
|
|
522
|
+
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
523
|
+
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function getAuthorizationServerInformationFromCredentials(credentials) {
|
|
527
|
+
if (!(credentials == null ? void 0 : credentials.authorization_server) || !credentials.token_endpoint) {
|
|
528
|
+
return void 0;
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
authorizationServerUrl: normalizeUrl(credentials.authorization_server),
|
|
532
|
+
tokenEndpoint: normalizeUrl(credentials.token_endpoint)
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
async function getStoredAuthorizationServerInformation({
|
|
536
|
+
provider,
|
|
537
|
+
clientInformation,
|
|
538
|
+
tokens
|
|
539
|
+
}) {
|
|
540
|
+
var _a3;
|
|
541
|
+
const tokenAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(tokens);
|
|
542
|
+
if (tokenAuthorizationServerInformation) {
|
|
543
|
+
return tokenAuthorizationServerInformation;
|
|
544
|
+
}
|
|
545
|
+
const providerAuthorizationServerInformation = await ((_a3 = provider.authorizationServerInformation) == null ? void 0 : _a3.call(provider));
|
|
546
|
+
if (providerAuthorizationServerInformation) {
|
|
547
|
+
return {
|
|
548
|
+
authorizationServerUrl: normalizeUrl(
|
|
549
|
+
providerAuthorizationServerInformation.authorizationServerUrl
|
|
550
|
+
),
|
|
551
|
+
tokenEndpoint: normalizeUrl(
|
|
552
|
+
providerAuthorizationServerInformation.tokenEndpoint
|
|
553
|
+
)
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
return getAuthorizationServerInformationFromCredentials(clientInformation);
|
|
557
|
+
}
|
|
558
|
+
async function saveAuthorizationServerInformation({
|
|
559
|
+
provider,
|
|
560
|
+
clientInformation,
|
|
561
|
+
authorizationServerInformation
|
|
562
|
+
}) {
|
|
563
|
+
if (provider.saveAuthorizationServerInformation) {
|
|
564
|
+
await provider.saveAuthorizationServerInformation(
|
|
565
|
+
authorizationServerInformation
|
|
566
|
+
);
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
if (provider.saveClientInformation) {
|
|
570
|
+
await provider.saveClientInformation(
|
|
571
|
+
addAuthorizationServerInformationToClientInformation(
|
|
572
|
+
clientInformation,
|
|
573
|
+
authorizationServerInformation
|
|
574
|
+
)
|
|
575
|
+
);
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
function assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl) {
|
|
581
|
+
if (!resourceMetadataUrl) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const expectedOrigin = new URL(serverUrl).origin;
|
|
585
|
+
if (resourceMetadataUrl.origin !== expectedOrigin) {
|
|
586
|
+
throw new MCPClientOAuthError({
|
|
587
|
+
message: `OAuth protected resource metadata URL ${resourceMetadataUrl.href} must have the same origin as the MCP server URL ${expectedOrigin}`
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function assertAuthorizationServerInformationMatches({
|
|
592
|
+
storedAuthorizationServerInformation,
|
|
593
|
+
currentAuthorizationServerInformation
|
|
594
|
+
}) {
|
|
595
|
+
if (storedAuthorizationServerInformation.authorizationServerUrl !== currentAuthorizationServerInformation.authorizationServerUrl || storedAuthorizationServerInformation.tokenEndpoint !== currentAuthorizationServerInformation.tokenEndpoint) {
|
|
596
|
+
throw new MCPClientOAuthError({
|
|
597
|
+
message: "OAuth authorization server metadata does not match the metadata that issued the stored credentials"
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
497
601
|
function extractResourceMetadataUrl(response) {
|
|
498
602
|
var _a3;
|
|
499
603
|
const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
|
|
@@ -971,8 +1075,10 @@ async function authInternal(provider, {
|
|
|
971
1075
|
resourceMetadataUrl,
|
|
972
1076
|
fetchFn
|
|
973
1077
|
}) {
|
|
1078
|
+
var _a3;
|
|
974
1079
|
let resourceMetadata;
|
|
975
1080
|
let authorizationServerUrl;
|
|
1081
|
+
assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl);
|
|
976
1082
|
try {
|
|
977
1083
|
resourceMetadata = await discoverOAuthProtectedResourceMetadata(
|
|
978
1084
|
serverUrl,
|
|
@@ -998,6 +1104,7 @@ async function authInternal(provider, {
|
|
|
998
1104
|
fetchFn
|
|
999
1105
|
}
|
|
1000
1106
|
);
|
|
1107
|
+
const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
|
|
1001
1108
|
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1002
1109
|
if (!clientInformation) {
|
|
1003
1110
|
if (authorizationCode !== void 0) {
|
|
@@ -1015,8 +1122,11 @@ async function authInternal(provider, {
|
|
|
1015
1122
|
clientMetadata: provider.clientMetadata,
|
|
1016
1123
|
fetchFn
|
|
1017
1124
|
});
|
|
1018
|
-
|
|
1019
|
-
|
|
1125
|
+
clientInformation = addAuthorizationServerInformationToClientInformation(
|
|
1126
|
+
fullInformation,
|
|
1127
|
+
currentAuthorizationServerInformation
|
|
1128
|
+
);
|
|
1129
|
+
await provider.saveClientInformation(clientInformation);
|
|
1020
1130
|
}
|
|
1021
1131
|
if (authorizationCode !== void 0) {
|
|
1022
1132
|
if (provider.storedState) {
|
|
@@ -1027,6 +1137,19 @@ async function authInternal(provider, {
|
|
|
1027
1137
|
);
|
|
1028
1138
|
}
|
|
1029
1139
|
}
|
|
1140
|
+
const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
1141
|
+
provider,
|
|
1142
|
+
clientInformation
|
|
1143
|
+
});
|
|
1144
|
+
if (!storedAuthorizationServerInformation) {
|
|
1145
|
+
throw new MCPClientOAuthError({
|
|
1146
|
+
message: "Stored OAuth authorization server metadata is required when exchanging an authorization code"
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
assertAuthorizationServerInformationMatches({
|
|
1150
|
+
storedAuthorizationServerInformation,
|
|
1151
|
+
currentAuthorizationServerInformation
|
|
1152
|
+
});
|
|
1030
1153
|
const codeVerifier2 = await provider.codeVerifier();
|
|
1031
1154
|
const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
|
|
1032
1155
|
metadata,
|
|
@@ -1038,22 +1161,47 @@ async function authInternal(provider, {
|
|
|
1038
1161
|
addClientAuthentication: provider.addClientAuthentication,
|
|
1039
1162
|
fetchFn
|
|
1040
1163
|
});
|
|
1041
|
-
await provider.saveTokens(
|
|
1164
|
+
await provider.saveTokens(
|
|
1165
|
+
addAuthorizationServerInformationToTokens(
|
|
1166
|
+
tokens2,
|
|
1167
|
+
currentAuthorizationServerInformation
|
|
1168
|
+
)
|
|
1169
|
+
);
|
|
1042
1170
|
return "AUTHORIZED";
|
|
1043
1171
|
}
|
|
1044
1172
|
const tokens = await provider.tokens();
|
|
1045
1173
|
if (tokens == null ? void 0 : tokens.refresh_token) {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1174
|
+
const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
1175
|
+
provider,
|
|
1176
|
+
clientInformation,
|
|
1177
|
+
tokens
|
|
1178
|
+
});
|
|
1179
|
+
if (storedAuthorizationServerInformation) {
|
|
1180
|
+
assertAuthorizationServerInformationMatches({
|
|
1181
|
+
storedAuthorizationServerInformation,
|
|
1182
|
+
currentAuthorizationServerInformation
|
|
1054
1183
|
});
|
|
1055
|
-
|
|
1056
|
-
|
|
1184
|
+
} else {
|
|
1185
|
+
await ((_a3 = provider.invalidateCredentials) == null ? void 0 : _a3.call(provider, "tokens"));
|
|
1186
|
+
}
|
|
1187
|
+
try {
|
|
1188
|
+
if (storedAuthorizationServerInformation) {
|
|
1189
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
1190
|
+
metadata,
|
|
1191
|
+
clientInformation,
|
|
1192
|
+
refreshToken: tokens.refresh_token,
|
|
1193
|
+
resource,
|
|
1194
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
1195
|
+
fetchFn
|
|
1196
|
+
});
|
|
1197
|
+
await provider.saveTokens(
|
|
1198
|
+
addAuthorizationServerInformationToTokens(
|
|
1199
|
+
newTokens,
|
|
1200
|
+
currentAuthorizationServerInformation
|
|
1201
|
+
)
|
|
1202
|
+
);
|
|
1203
|
+
return "AUTHORIZED";
|
|
1204
|
+
}
|
|
1057
1205
|
} catch (error) {
|
|
1058
1206
|
if (
|
|
1059
1207
|
// If this is a ServerError, or an unknown type, log it out and try to continue. Otherwise, escalate so we can fix things and retry.
|
|
@@ -1079,6 +1227,16 @@ async function authInternal(provider, {
|
|
|
1079
1227
|
resource
|
|
1080
1228
|
}
|
|
1081
1229
|
);
|
|
1230
|
+
const savedAuthorizationServerInformation = await saveAuthorizationServerInformation({
|
|
1231
|
+
provider,
|
|
1232
|
+
clientInformation,
|
|
1233
|
+
authorizationServerInformation: currentAuthorizationServerInformation
|
|
1234
|
+
});
|
|
1235
|
+
if (!savedAuthorizationServerInformation) {
|
|
1236
|
+
throw new MCPClientOAuthError({
|
|
1237
|
+
message: "OAuth authorization server metadata must be saveable before starting authorization"
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1082
1240
|
await provider.saveCodeVerifier(codeVerifier);
|
|
1083
1241
|
await provider.redirectToAuthorization(authorizationUrl);
|
|
1084
1242
|
return "REDIRECT";
|