@ai-sdk/mcp 0.0.17 → 0.0.19

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,34 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 0.0.19
4
+
5
+ ### Patch Changes
6
+
7
+ - d872a7a: fix(mcp): lock first sse endpoint received via event
8
+ - f4cd468: fix(mcp): prevent prototype-named tools from bypassing the `schemas` allowlist
9
+
10
+ When using `client.tools({ schemas })` to expose only an explicitly allowed
11
+ subset of an MCP server's tools, the allowlist check used the `in` operator,
12
+ which also matches inherited `Object.prototype` properties. A server-advertised
13
+ tool named `constructor`, `toString`, `__proto__`, etc. would pass the check
14
+ even though the developer never defined it in `schemas`, and was then exposed to
15
+ the model and executable. The check now uses `Object.hasOwn`, so only
16
+ explicitly defined tools are returned.
17
+
18
+ - Updated dependencies [9f67efe]
19
+ - Updated dependencies [eea9166]
20
+ - @ai-sdk/provider-utils@3.0.26
21
+
22
+ ## 0.0.18
23
+
24
+ ### Patch Changes
25
+
26
+ - 783fa6c: chore: ensure consistent import handling and avoid import duplicates or cycles
27
+ - c327fb9: fix(mcp): prevent prototype pollution by using secureJsonParse
28
+ - Updated dependencies [783fa6c]
29
+ - @ai-sdk/provider-utils@3.0.25
30
+ - @ai-sdk/provider@2.0.3
31
+
3
32
  ## 0.0.17
4
33
 
5
34
  ### Patch Changes
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ __export(index_exports, {
39
39
  module.exports = __toCommonJS(index_exports);
40
40
 
41
41
  // src/tool/mcp-client.ts
42
- var import_provider_utils3 = require("@ai-sdk/provider-utils");
42
+ var import_provider_utils5 = require("@ai-sdk/provider-utils");
43
43
 
44
44
  // src/error/mcp-client-error.ts
45
45
  var import_provider = require("@ai-sdk/provider");
@@ -66,9 +66,10 @@ var MCPClientError = class extends (_b = import_provider.AISDKError, _a = symbol
66
66
  };
67
67
 
68
68
  // src/tool/mcp-sse-transport.ts
69
- var import_provider_utils = require("@ai-sdk/provider-utils");
69
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
70
70
 
71
71
  // src/tool/json-rpc-message.ts
72
+ var import_provider_utils = require("@ai-sdk/provider-utils");
72
73
  var import_v42 = require("zod/v4");
73
74
 
74
75
  // src/tool/types.ts
@@ -288,6 +289,9 @@ var JSONRPCMessageSchema = import_v42.z.union([
288
289
  JSONRPCResponseSchema,
289
290
  JSONRPCErrorSchema
290
291
  ]);
292
+ async function parseJSONRPCMessage(text) {
293
+ return JSONRPCMessageSchema.parse(await (0, import_provider_utils.parseJSON)({ text }));
294
+ }
291
295
 
292
296
  // src/version.ts
293
297
  var VERSION = typeof __PACKAGE_VERSION__ !== "undefined" ? __PACKAGE_VERSION__ : "0.0.0-test";
@@ -465,6 +469,7 @@ function checkResourceAllowed({
465
469
  }
466
470
 
467
471
  // src/tool/oauth.ts
472
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
468
473
  var UnauthorizedError = class extends Error {
469
474
  constructor(message = "Unauthorized") {
470
475
  super(message);
@@ -743,7 +748,9 @@ async function parseErrorResponse(input) {
743
748
  const statusCode = input instanceof Response ? input.status : void 0;
744
749
  const body = input instanceof Response ? await input.text() : input;
745
750
  try {
746
- const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
751
+ const result = OAuthErrorResponseSchema.parse(
752
+ await (0, import_provider_utils2.parseJSON)({ text: body })
753
+ );
747
754
  const { error, error_description, error_uri } = result;
748
755
  const errorClass = OAUTH_ERRORS[error] || ServerError;
749
756
  return new errorClass({
@@ -1057,10 +1064,10 @@ var SseMCPTransport = class {
1057
1064
  headers["Authorization"] = `Bearer ${tokens.access_token}`;
1058
1065
  }
1059
1066
  }
1060
- return (0, import_provider_utils.withUserAgentSuffix)(
1067
+ return (0, import_provider_utils3.withUserAgentSuffix)(
1061
1068
  headers,
1062
1069
  `ai-sdk/${VERSION}`,
1063
- (0, import_provider_utils.getRuntimeEnvironmentUserAgent)()
1070
+ (0, import_provider_utils3.getRuntimeEnvironmentUserAgent)()
1064
1071
  );
1065
1072
  }
1066
1073
  async start() {
@@ -1108,10 +1115,10 @@ var SseMCPTransport = class {
1108
1115
  (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1109
1116
  return reject(error);
1110
1117
  }
1111
- const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils.EventSourceParserStream());
1118
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils3.EventSourceParserStream());
1112
1119
  const reader = stream.getReader();
1113
1120
  const processEvents = async () => {
1114
- var _a4, _b4, _c2;
1121
+ var _a4, _b4, _c2, _d2, _e2;
1115
1122
  try {
1116
1123
  while (true) {
1117
1124
  const { done, value } = await reader.read();
@@ -1126,26 +1133,32 @@ var SseMCPTransport = class {
1126
1133
  }
1127
1134
  const { event, data } = value;
1128
1135
  if (event === "endpoint") {
1129
- this.endpoint = new URL(data, this.url);
1130
- if (this.endpoint.origin !== this.url.origin) {
1136
+ if (this.endpoint) {
1137
+ continue;
1138
+ }
1139
+ const endpoint = new URL(data, this.url);
1140
+ if (endpoint.origin !== this.url.origin) {
1141
+ this.connected = false;
1142
+ this.endpoint = void 0;
1143
+ (_a4 = this.sseConnection) == null ? void 0 : _a4.close();
1144
+ (_b4 = this.abortController) == null ? void 0 : _b4.abort();
1131
1145
  throw new MCPClientError({
1132
- message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${this.endpoint.origin}`
1146
+ message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${endpoint.origin}`
1133
1147
  });
1134
1148
  }
1149
+ this.endpoint = endpoint;
1135
1150
  this.connected = true;
1136
1151
  resolve();
1137
1152
  } else if (event === "message") {
1138
1153
  try {
1139
- const message = JSONRPCMessageSchema.parse(
1140
- JSON.parse(data)
1141
- );
1142
- (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, message);
1154
+ const message = await parseJSONRPCMessage(data);
1155
+ (_c2 = this.onmessage) == null ? void 0 : _c2.call(this, message);
1143
1156
  } catch (error) {
1144
1157
  const e = new MCPClientError({
1145
1158
  message: "MCP SSE Transport Error: Failed to parse message",
1146
1159
  cause: error
1147
1160
  });
1148
- (_b4 = this.onerror) == null ? void 0 : _b4.call(this, e);
1161
+ (_d2 = this.onerror) == null ? void 0 : _d2.call(this, e);
1149
1162
  }
1150
1163
  }
1151
1164
  }
@@ -1153,7 +1166,7 @@ var SseMCPTransport = class {
1153
1166
  if (error instanceof Error && error.name === "AbortError") {
1154
1167
  return;
1155
1168
  }
1156
- (_c2 = this.onerror) == null ? void 0 : _c2.call(this, error);
1169
+ (_e2 = this.onerror) == null ? void 0 : _e2.call(this, error);
1157
1170
  reject(error);
1158
1171
  }
1159
1172
  };
@@ -1175,6 +1188,7 @@ var SseMCPTransport = class {
1175
1188
  async close() {
1176
1189
  var _a3, _b3, _c;
1177
1190
  this.connected = false;
1191
+ this.endpoint = void 0;
1178
1192
  (_a3 = this.sseConnection) == null ? void 0 : _a3.close();
1179
1193
  (_b3 = this.abortController) == null ? void 0 : _b3.abort();
1180
1194
  (_c = this.onclose) == null ? void 0 : _c.call(this);
@@ -1235,7 +1249,7 @@ var SseMCPTransport = class {
1235
1249
  };
1236
1250
 
1237
1251
  // src/tool/mcp-http-transport.ts
1238
- var import_provider_utils2 = require("@ai-sdk/provider-utils");
1252
+ var import_provider_utils4 = require("@ai-sdk/provider-utils");
1239
1253
  var HttpMCPTransport = class {
1240
1254
  constructor({
1241
1255
  url,
@@ -1268,10 +1282,10 @@ var HttpMCPTransport = class {
1268
1282
  headers["Authorization"] = `Bearer ${tokens.access_token}`;
1269
1283
  }
1270
1284
  }
1271
- return (0, import_provider_utils2.withUserAgentSuffix)(
1285
+ return (0, import_provider_utils4.withUserAgentSuffix)(
1272
1286
  headers,
1273
1287
  `ai-sdk/${VERSION}`,
1274
- (0, import_provider_utils2.getRuntimeEnvironmentUserAgent)()
1288
+ (0, import_provider_utils4.getRuntimeEnvironmentUserAgent)()
1275
1289
  );
1276
1290
  }
1277
1291
  async start() {
@@ -1369,7 +1383,7 @@ var HttpMCPTransport = class {
1369
1383
  (_e = this.onerror) == null ? void 0 : _e.call(this, error2);
1370
1384
  throw error2;
1371
1385
  }
1372
- const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils2.EventSourceParserStream());
1386
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils4.EventSourceParserStream());
1373
1387
  const reader = stream.getReader();
1374
1388
  const processEvents = async () => {
1375
1389
  var _a4, _b4, _c2;
@@ -1380,7 +1394,7 @@ var HttpMCPTransport = class {
1380
1394
  const { event, data } = value;
1381
1395
  if (event === "message") {
1382
1396
  try {
1383
- const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
1397
+ const msg = await parseJSONRPCMessage(data);
1384
1398
  (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, msg);
1385
1399
  } catch (error2) {
1386
1400
  const e = new MCPClientError({
@@ -1491,7 +1505,7 @@ var HttpMCPTransport = class {
1491
1505
  (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1492
1506
  return;
1493
1507
  }
1494
- const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils2.EventSourceParserStream());
1508
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils4.EventSourceParserStream());
1495
1509
  const reader = stream.getReader();
1496
1510
  const processEvents = async () => {
1497
1511
  var _a4, _b4, _c2, _d2;
@@ -1505,7 +1519,7 @@ var HttpMCPTransport = class {
1505
1519
  }
1506
1520
  if (event === "message") {
1507
1521
  try {
1508
- const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
1522
+ const msg = await parseJSONRPCMessage(data);
1509
1523
  (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, msg);
1510
1524
  } catch (error) {
1511
1525
  const e = new MCPClientError({
@@ -1858,7 +1872,7 @@ var DefaultMCPClient = class {
1858
1872
  try {
1859
1873
  const listToolsResult = await this.listTools();
1860
1874
  for (const { name: name3, description, inputSchema } of listToolsResult.tools) {
1861
- if (schemas !== "automatic" && !(name3 in schemas)) {
1875
+ if (schemas !== "automatic" && !Object.prototype.hasOwnProperty.call(schemas, name3)) {
1862
1876
  continue;
1863
1877
  }
1864
1878
  const self = this;
@@ -1867,15 +1881,15 @@ var DefaultMCPClient = class {
1867
1881
  (_a4 = options == null ? void 0 : options.abortSignal) == null ? void 0 : _a4.throwIfAborted();
1868
1882
  return self.callTool({ name: name3, args, options });
1869
1883
  };
1870
- const toolWithExecute = schemas === "automatic" ? (0, import_provider_utils3.dynamicTool)({
1884
+ const toolWithExecute = schemas === "automatic" ? (0, import_provider_utils5.dynamicTool)({
1871
1885
  description,
1872
- inputSchema: (0, import_provider_utils3.jsonSchema)({
1886
+ inputSchema: (0, import_provider_utils5.jsonSchema)({
1873
1887
  ...inputSchema,
1874
1888
  properties: (_a3 = inputSchema.properties) != null ? _a3 : {},
1875
1889
  additionalProperties: false
1876
1890
  }),
1877
1891
  execute
1878
- }) : (0, import_provider_utils3.tool)({
1892
+ }) : (0, import_provider_utils5.tool)({
1879
1893
  description,
1880
1894
  inputSchema: schemas[name3].inputSchema,
1881
1895
  execute