@ai-sdk/mcp 1.0.45 → 1.0.47

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,17 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 1.0.47
4
+
5
+ ### Patch Changes
6
+
7
+ - bf1d6bd: fix(mcp): prevent mcp oauth credential exfiltration during rediscovery
8
+
9
+ ## 1.0.46
10
+
11
+ ### Patch Changes
12
+
13
+ - 1f817db: fix(mcp): await addClientAuthentication in token exchange and refresh
14
+
3
15
  ## 1.0.45
4
16
 
5
17
  ### Patch Changes
package/dist/index.d.mts 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>;
@@ -561,4 +571,4 @@ interface MCPClient {
561
571
  close: () => Promise<void>;
562
572
  }
563
573
 
564
- export { type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, 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 };
574
+ export { type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, 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 };
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>;
@@ -561,4 +571,4 @@ interface MCPClient {
561
571
  close: () => Promise<void>;
562
572
  }
563
573
 
564
- export { type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, 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 };
574
+ export { type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type JSONRPCError, type JSONRPCMessage, type JSONRPCNotification, type JSONRPCRequest, type JSONRPCResponse, type ListToolsResult, type MCPClient, type ClientCapabilities as MCPClientCapabilities, type MCPClientConfig, type MCPTransport, 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 };
package/dist/index.js CHANGED
@@ -342,15 +342,6 @@ var import_pkce_challenge = __toESM(require("pkce-challenge"));
342
342
 
343
343
  // src/tool/oauth-types.ts
344
344
  var import_v43 = require("zod/v4");
345
- var OAuthTokensSchema = import_v43.z.object({
346
- access_token: import_v43.z.string(),
347
- id_token: import_v43.z.string().optional(),
348
- // Optional for OAuth 2.1, but necessary in OpenID Connect
349
- token_type: import_v43.z.string(),
350
- expires_in: import_v43.z.number().optional(),
351
- scope: import_v43.z.string().optional(),
352
- refresh_token: import_v43.z.string().optional()
353
- }).strip();
354
345
  var SafeUrlSchema = import_v43.z.string().url().superRefine((val, ctx) => {
355
346
  if (!URL.canParse(val)) {
356
347
  ctx.addIssue({
@@ -367,6 +358,17 @@ var SafeUrlSchema = import_v43.z.string().url().superRefine((val, ctx) => {
367
358
  },
368
359
  { message: "URL cannot use javascript:, data:, or vbscript: scheme" }
369
360
  );
361
+ var OAuthTokensSchema = import_v43.z.object({
362
+ access_token: import_v43.z.string(),
363
+ id_token: import_v43.z.string().optional(),
364
+ // Optional for OAuth 2.1, but necessary in OpenID Connect
365
+ token_type: import_v43.z.string(),
366
+ expires_in: import_v43.z.number().optional(),
367
+ scope: import_v43.z.string().optional(),
368
+ refresh_token: import_v43.z.string().optional(),
369
+ authorization_server: SafeUrlSchema.optional(),
370
+ token_endpoint: SafeUrlSchema.optional()
371
+ }).strip();
370
372
  var OAuthProtectedResourceMetadataSchema = import_v43.z.object({
371
373
  resource: import_v43.z.string().url(),
372
374
  authorization_servers: import_v43.z.array(SafeUrlSchema).optional(),
@@ -419,7 +421,9 @@ var OAuthClientInformationSchema = import_v43.z.object({
419
421
  client_id: import_v43.z.string(),
420
422
  client_secret: import_v43.z.string().optional(),
421
423
  client_id_issued_at: import_v43.z.number().optional(),
422
- client_secret_expires_at: import_v43.z.number().optional()
424
+ client_secret_expires_at: import_v43.z.number().optional(),
425
+ authorization_server: SafeUrlSchema.optional(),
426
+ token_endpoint: SafeUrlSchema.optional()
423
427
  }).strip();
424
428
  var OAuthClientMetadataSchema = import_v43.z.object({
425
429
  redirect_uris: import_v43.z.array(SafeUrlSchema),
@@ -524,6 +528,106 @@ var UnauthorizedError = class extends Error {
524
528
  this.name = "UnauthorizedError";
525
529
  }
526
530
  };
531
+ function normalizeUrl(url) {
532
+ return new URL(url).href;
533
+ }
534
+ function createAuthorizationServerInformation(authorizationServerUrl, metadata) {
535
+ return {
536
+ authorizationServerUrl: normalizeUrl(authorizationServerUrl),
537
+ tokenEndpoint: normalizeUrl(
538
+ (metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl)
539
+ )
540
+ };
541
+ }
542
+ function addAuthorizationServerInformationToTokens(tokens, authorizationServerInformation) {
543
+ return {
544
+ ...tokens,
545
+ authorization_server: authorizationServerInformation.authorizationServerUrl,
546
+ token_endpoint: authorizationServerInformation.tokenEndpoint
547
+ };
548
+ }
549
+ function addAuthorizationServerInformationToClientInformation(clientInformation, authorizationServerInformation) {
550
+ return {
551
+ ...clientInformation,
552
+ authorization_server: authorizationServerInformation.authorizationServerUrl,
553
+ token_endpoint: authorizationServerInformation.tokenEndpoint
554
+ };
555
+ }
556
+ function getAuthorizationServerInformationFromCredentials(credentials) {
557
+ if (!(credentials == null ? void 0 : credentials.authorization_server) || !credentials.token_endpoint) {
558
+ return void 0;
559
+ }
560
+ return {
561
+ authorizationServerUrl: normalizeUrl(credentials.authorization_server),
562
+ tokenEndpoint: normalizeUrl(credentials.token_endpoint)
563
+ };
564
+ }
565
+ async function getStoredAuthorizationServerInformation({
566
+ provider,
567
+ clientInformation,
568
+ tokens
569
+ }) {
570
+ var _a3;
571
+ const tokenAuthorizationServerInformation = getAuthorizationServerInformationFromCredentials(tokens);
572
+ if (tokenAuthorizationServerInformation) {
573
+ return tokenAuthorizationServerInformation;
574
+ }
575
+ const providerAuthorizationServerInformation = await ((_a3 = provider.authorizationServerInformation) == null ? void 0 : _a3.call(provider));
576
+ if (providerAuthorizationServerInformation) {
577
+ return {
578
+ authorizationServerUrl: normalizeUrl(
579
+ providerAuthorizationServerInformation.authorizationServerUrl
580
+ ),
581
+ tokenEndpoint: normalizeUrl(
582
+ providerAuthorizationServerInformation.tokenEndpoint
583
+ )
584
+ };
585
+ }
586
+ return getAuthorizationServerInformationFromCredentials(clientInformation);
587
+ }
588
+ async function saveAuthorizationServerInformation({
589
+ provider,
590
+ clientInformation,
591
+ authorizationServerInformation
592
+ }) {
593
+ if (provider.saveAuthorizationServerInformation) {
594
+ await provider.saveAuthorizationServerInformation(
595
+ authorizationServerInformation
596
+ );
597
+ return true;
598
+ }
599
+ if (provider.saveClientInformation) {
600
+ await provider.saveClientInformation(
601
+ addAuthorizationServerInformationToClientInformation(
602
+ clientInformation,
603
+ authorizationServerInformation
604
+ )
605
+ );
606
+ return true;
607
+ }
608
+ return false;
609
+ }
610
+ function assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl) {
611
+ if (!resourceMetadataUrl) {
612
+ return;
613
+ }
614
+ const expectedOrigin = new URL(serverUrl).origin;
615
+ if (resourceMetadataUrl.origin !== expectedOrigin) {
616
+ throw new MCPClientOAuthError({
617
+ message: `OAuth protected resource metadata URL ${resourceMetadataUrl.href} must have the same origin as the MCP server URL ${expectedOrigin}`
618
+ });
619
+ }
620
+ }
621
+ function assertAuthorizationServerInformationMatches({
622
+ storedAuthorizationServerInformation,
623
+ currentAuthorizationServerInformation
624
+ }) {
625
+ if (storedAuthorizationServerInformation.authorizationServerUrl !== currentAuthorizationServerInformation.authorizationServerUrl || storedAuthorizationServerInformation.tokenEndpoint !== currentAuthorizationServerInformation.tokenEndpoint) {
626
+ throw new MCPClientOAuthError({
627
+ message: "OAuth authorization server metadata does not match the metadata that issued the stored credentials"
628
+ });
629
+ }
630
+ }
527
631
  function extractResourceMetadataUrl(response) {
528
632
  var _a3;
529
633
  const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
@@ -842,7 +946,12 @@ async function exchangeAuthorization(authorizationServerUrl, {
842
946
  redirect_uri: String(redirectUri)
843
947
  });
844
948
  if (addClientAuthentication) {
845
- addClientAuthentication(headers, params, authorizationServerUrl, metadata);
949
+ await addClientAuthentication(
950
+ headers,
951
+ params,
952
+ authorizationServerUrl,
953
+ metadata
954
+ );
846
955
  } else {
847
956
  const supportedMethods = (_a3 = metadata == null ? void 0 : metadata.token_endpoint_auth_methods_supported) != null ? _a3 : [];
848
957
  const authMethod = selectClientAuthMethod(
@@ -894,7 +1003,12 @@ async function refreshAuthorization(authorizationServerUrl, {
894
1003
  refresh_token: refreshToken
895
1004
  });
896
1005
  if (addClientAuthentication) {
897
- addClientAuthentication(headers, params, authorizationServerUrl, metadata);
1006
+ await addClientAuthentication(
1007
+ headers,
1008
+ params,
1009
+ authorizationServerUrl,
1010
+ metadata
1011
+ );
898
1012
  } else {
899
1013
  const supportedMethods = (_a3 = metadata == null ? void 0 : metadata.token_endpoint_auth_methods_supported) != null ? _a3 : [];
900
1014
  const authMethod = selectClientAuthMethod(
@@ -991,8 +1105,10 @@ async function authInternal(provider, {
991
1105
  resourceMetadataUrl,
992
1106
  fetchFn
993
1107
  }) {
1108
+ var _a3;
994
1109
  let resourceMetadata;
995
1110
  let authorizationServerUrl;
1111
+ assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl);
996
1112
  try {
997
1113
  resourceMetadata = await discoverOAuthProtectedResourceMetadata(
998
1114
  serverUrl,
@@ -1018,6 +1134,7 @@ async function authInternal(provider, {
1018
1134
  fetchFn
1019
1135
  }
1020
1136
  );
1137
+ const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
1021
1138
  let clientInformation = await Promise.resolve(provider.clientInformation());
1022
1139
  if (!clientInformation) {
1023
1140
  if (authorizationCode !== void 0) {
@@ -1035,8 +1152,11 @@ async function authInternal(provider, {
1035
1152
  clientMetadata: provider.clientMetadata,
1036
1153
  fetchFn
1037
1154
  });
1038
- await provider.saveClientInformation(fullInformation);
1039
- clientInformation = fullInformation;
1155
+ clientInformation = addAuthorizationServerInformationToClientInformation(
1156
+ fullInformation,
1157
+ currentAuthorizationServerInformation
1158
+ );
1159
+ await provider.saveClientInformation(clientInformation);
1040
1160
  }
1041
1161
  if (authorizationCode !== void 0) {
1042
1162
  if (provider.storedState) {
@@ -1047,6 +1167,19 @@ async function authInternal(provider, {
1047
1167
  );
1048
1168
  }
1049
1169
  }
1170
+ const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
1171
+ provider,
1172
+ clientInformation
1173
+ });
1174
+ if (!storedAuthorizationServerInformation) {
1175
+ throw new MCPClientOAuthError({
1176
+ message: "Stored OAuth authorization server metadata is required when exchanging an authorization code"
1177
+ });
1178
+ }
1179
+ assertAuthorizationServerInformationMatches({
1180
+ storedAuthorizationServerInformation,
1181
+ currentAuthorizationServerInformation
1182
+ });
1050
1183
  const codeVerifier2 = await provider.codeVerifier();
1051
1184
  const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
1052
1185
  metadata,
@@ -1058,22 +1191,47 @@ async function authInternal(provider, {
1058
1191
  addClientAuthentication: provider.addClientAuthentication,
1059
1192
  fetchFn
1060
1193
  });
1061
- await provider.saveTokens(tokens2);
1194
+ await provider.saveTokens(
1195
+ addAuthorizationServerInformationToTokens(
1196
+ tokens2,
1197
+ currentAuthorizationServerInformation
1198
+ )
1199
+ );
1062
1200
  return "AUTHORIZED";
1063
1201
  }
1064
1202
  const tokens = await provider.tokens();
1065
1203
  if (tokens == null ? void 0 : tokens.refresh_token) {
1066
- try {
1067
- const newTokens = await refreshAuthorization(authorizationServerUrl, {
1068
- metadata,
1069
- clientInformation,
1070
- refreshToken: tokens.refresh_token,
1071
- resource,
1072
- addClientAuthentication: provider.addClientAuthentication,
1073
- fetchFn
1204
+ const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
1205
+ provider,
1206
+ clientInformation,
1207
+ tokens
1208
+ });
1209
+ if (storedAuthorizationServerInformation) {
1210
+ assertAuthorizationServerInformationMatches({
1211
+ storedAuthorizationServerInformation,
1212
+ currentAuthorizationServerInformation
1074
1213
  });
1075
- await provider.saveTokens(newTokens);
1076
- return "AUTHORIZED";
1214
+ } else {
1215
+ await ((_a3 = provider.invalidateCredentials) == null ? void 0 : _a3.call(provider, "tokens"));
1216
+ }
1217
+ try {
1218
+ if (storedAuthorizationServerInformation) {
1219
+ const newTokens = await refreshAuthorization(authorizationServerUrl, {
1220
+ metadata,
1221
+ clientInformation,
1222
+ refreshToken: tokens.refresh_token,
1223
+ resource,
1224
+ addClientAuthentication: provider.addClientAuthentication,
1225
+ fetchFn
1226
+ });
1227
+ await provider.saveTokens(
1228
+ addAuthorizationServerInformationToTokens(
1229
+ newTokens,
1230
+ currentAuthorizationServerInformation
1231
+ )
1232
+ );
1233
+ return "AUTHORIZED";
1234
+ }
1077
1235
  } catch (error) {
1078
1236
  if (
1079
1237
  // 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.
@@ -1099,6 +1257,16 @@ async function authInternal(provider, {
1099
1257
  resource
1100
1258
  }
1101
1259
  );
1260
+ const savedAuthorizationServerInformation = await saveAuthorizationServerInformation({
1261
+ provider,
1262
+ clientInformation,
1263
+ authorizationServerInformation: currentAuthorizationServerInformation
1264
+ });
1265
+ if (!savedAuthorizationServerInformation) {
1266
+ throw new MCPClientOAuthError({
1267
+ message: "OAuth authorization server metadata must be saveable before starting authorization"
1268
+ });
1269
+ }
1102
1270
  await provider.saveCodeVerifier(codeVerifier);
1103
1271
  await provider.redirectToAuthorization(authorizationUrl);
1104
1272
  return "REDIRECT";