@ai-sdk/mcp 1.0.27 → 1.0.29

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.29
4
+
5
+ ### Patch Changes
6
+
7
+ - cc8b506: feat(mcp): add `redirect` option to `MCPTransportConfig` for controlling HTTP redirect behavior
8
+
9
+ ## 1.0.28
10
+
11
+ ### Patch Changes
12
+
13
+ - 0c86a13: fix(mcp): validate state param in oauth flow
14
+
3
15
  ## 1.0.27
4
16
 
5
17
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -182,6 +182,8 @@ interface OAuthClientProvider {
182
182
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
183
183
  saveClientInformation?(clientInformation: OAuthClientInformation): void | Promise<void>;
184
184
  state?(): string | Promise<string>;
185
+ saveState?(state: string): void | Promise<void>;
186
+ storedState?(): string | undefined | Promise<string | undefined>;
185
187
  validateResourceURL?(serverUrl: string | URL, resource?: string): Promise<URL | undefined>;
186
188
  }
187
189
  declare class UnauthorizedError extends Error {
@@ -190,6 +192,7 @@ declare class UnauthorizedError extends Error {
190
192
  declare function auth(provider: OAuthClientProvider, options: {
191
193
  serverUrl: string | URL;
192
194
  authorizationCode?: string;
195
+ callbackState?: string;
193
196
  scope?: string;
194
197
  resourceMetadataUrl?: URL;
195
198
  fetchFn?: FetchFunction;
@@ -240,6 +243,13 @@ type MCPTransportConfig = {
240
243
  * An optional OAuth client provider to use for authentication for MCP servers.
241
244
  */
242
245
  authProvider?: OAuthClientProvider;
246
+ /**
247
+ * Controls how HTTP redirects are handled for transport requests.
248
+ * - `'follow'`: Follow redirects automatically (standard fetch behavior).
249
+ * - `'error'`: Reject any redirect response with an error.
250
+ * @default 'follow'
251
+ */
252
+ redirect?: 'follow' | 'error';
243
253
  };
244
254
 
245
255
  /** MCP tool metadata - keys should follow MCP _meta key format specification */
package/dist/index.d.ts CHANGED
@@ -182,6 +182,8 @@ interface OAuthClientProvider {
182
182
  clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
183
183
  saveClientInformation?(clientInformation: OAuthClientInformation): void | Promise<void>;
184
184
  state?(): string | Promise<string>;
185
+ saveState?(state: string): void | Promise<void>;
186
+ storedState?(): string | undefined | Promise<string | undefined>;
185
187
  validateResourceURL?(serverUrl: string | URL, resource?: string): Promise<URL | undefined>;
186
188
  }
187
189
  declare class UnauthorizedError extends Error {
@@ -190,6 +192,7 @@ declare class UnauthorizedError extends Error {
190
192
  declare function auth(provider: OAuthClientProvider, options: {
191
193
  serverUrl: string | URL;
192
194
  authorizationCode?: string;
195
+ callbackState?: string;
193
196
  scope?: string;
194
197
  resourceMetadataUrl?: URL;
195
198
  fetchFn?: FetchFunction;
@@ -240,6 +243,13 @@ type MCPTransportConfig = {
240
243
  * An optional OAuth client provider to use for authentication for MCP servers.
241
244
  */
242
245
  authProvider?: OAuthClientProvider;
246
+ /**
247
+ * Controls how HTTP redirects are handled for transport requests.
248
+ * - `'follow'`: Follow redirects automatically (standard fetch behavior).
249
+ * - `'error'`: Reject any redirect response with an error.
250
+ * @default 'follow'
251
+ */
252
+ redirect?: 'follow' | 'error';
243
253
  };
244
254
 
245
255
  /** MCP tool metadata - keys should follow MCP _meta key format specification */
package/dist/index.js CHANGED
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
33
  ElicitResultSchema: () => ElicitResultSchema,
34
34
  ElicitationRequestSchema: () => ElicitationRequestSchema,
35
35
  UnauthorizedError: () => UnauthorizedError,
@@ -37,7 +37,7 @@ __export(src_exports, {
37
37
  createMCPClient: () => createMCPClient,
38
38
  experimental_createMCPClient: () => createMCPClient
39
39
  });
40
- module.exports = __toCommonJS(src_exports);
40
+ module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/tool/mcp-client.ts
43
43
  var import_provider_utils3 = require("@ai-sdk/provider-utils");
@@ -949,6 +949,7 @@ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
949
949
  async function authInternal(provider, {
950
950
  serverUrl,
951
951
  authorizationCode,
952
+ callbackState,
952
953
  scope,
953
954
  resourceMetadataUrl,
954
955
  fetchFn
@@ -1001,6 +1002,14 @@ async function authInternal(provider, {
1001
1002
  clientInformation = fullInformation;
1002
1003
  }
1003
1004
  if (authorizationCode !== void 0) {
1005
+ if (provider.storedState) {
1006
+ const expectedState = await provider.storedState();
1007
+ if (expectedState !== void 0 && expectedState !== callbackState) {
1008
+ throw new Error(
1009
+ "OAuth state parameter mismatch - possible CSRF attack"
1010
+ );
1011
+ }
1012
+ }
1004
1013
  const codeVerifier2 = await provider.codeVerifier();
1005
1014
  const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
1006
1015
  metadata,
@@ -1039,6 +1048,9 @@ async function authInternal(provider, {
1039
1048
  }
1040
1049
  }
1041
1050
  const state = provider.state ? await provider.state() : void 0;
1051
+ if (state && provider.saveState) {
1052
+ await provider.saveState(state);
1053
+ }
1042
1054
  const { authorizationUrl, codeVerifier } = await startAuthorization(
1043
1055
  authorizationServerUrl,
1044
1056
  {
@@ -1060,12 +1072,14 @@ var SseMCPTransport = class {
1060
1072
  constructor({
1061
1073
  url,
1062
1074
  headers,
1063
- authProvider
1075
+ authProvider,
1076
+ redirect = "follow"
1064
1077
  }) {
1065
1078
  this.connected = false;
1066
1079
  this.url = new URL(url);
1067
1080
  this.headers = headers;
1068
1081
  this.authProvider = authProvider;
1082
+ this.redirectMode = redirect;
1069
1083
  }
1070
1084
  async commonHeaders(base) {
1071
1085
  const headers = {
@@ -1099,7 +1113,8 @@ var SseMCPTransport = class {
1099
1113
  });
1100
1114
  const response = await fetch(this.url.href, {
1101
1115
  headers,
1102
- signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1116
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
1117
+ redirect: this.redirectMode
1103
1118
  });
1104
1119
  if (response.status === 401 && this.authProvider && !triedAuth) {
1105
1120
  this.resourceMetadataUrl = extractResourceMetadataUrl(response);
@@ -1218,7 +1233,8 @@ var SseMCPTransport = class {
1218
1233
  method: "POST",
1219
1234
  headers,
1220
1235
  body: JSON.stringify(message),
1221
- signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1236
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
1237
+ redirect: this.redirectMode
1222
1238
  };
1223
1239
  const response = await fetch(endpoint, init);
1224
1240
  if (response.status === 401 && this.authProvider && !triedAuth) {
@@ -1262,7 +1278,8 @@ var HttpMCPTransport = class {
1262
1278
  constructor({
1263
1279
  url,
1264
1280
  headers,
1265
- authProvider
1281
+ authProvider,
1282
+ redirect = "follow"
1266
1283
  }) {
1267
1284
  this.inboundReconnectAttempts = 0;
1268
1285
  this.reconnectionOptions = {
@@ -1274,6 +1291,7 @@ var HttpMCPTransport = class {
1274
1291
  this.url = new URL(url);
1275
1292
  this.headers = headers;
1276
1293
  this.authProvider = authProvider;
1294
+ this.redirectMode = redirect;
1277
1295
  }
1278
1296
  async commonHeaders(base) {
1279
1297
  const headers = {
@@ -1314,7 +1332,8 @@ var HttpMCPTransport = class {
1314
1332
  await fetch(this.url, {
1315
1333
  method: "DELETE",
1316
1334
  headers,
1317
- signal: this.abortController.signal
1335
+ signal: this.abortController.signal,
1336
+ redirect: this.redirectMode
1318
1337
  }).catch(() => void 0);
1319
1338
  }
1320
1339
  } catch (e) {
@@ -1334,7 +1353,8 @@ var HttpMCPTransport = class {
1334
1353
  method: "POST",
1335
1354
  headers,
1336
1355
  body: JSON.stringify(message),
1337
- signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1356
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
1357
+ redirect: this.redirectMode
1338
1358
  };
1339
1359
  const response = await fetch(this.url, init);
1340
1360
  const sessionId = response.headers.get("mcp-session-id");
@@ -1483,7 +1503,8 @@ var HttpMCPTransport = class {
1483
1503
  const response = await fetch(this.url.href, {
1484
1504
  method: "GET",
1485
1505
  headers,
1486
- signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1506
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal,
1507
+ redirect: this.redirectMode
1487
1508
  });
1488
1509
  const sessionId = response.headers.get("mcp-session-id");
1489
1510
  if (sessionId) {