@ai-sdk/mcp 2.0.4 → 2.0.6

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,21 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 2.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 3c30eb4: feat(mcp): expose a json-rpc message validator
8
+ - Updated dependencies [c6f5e62]
9
+ - @ai-sdk/provider-utils@5.0.4
10
+
11
+ ## 2.0.5
12
+
13
+ ### Patch Changes
14
+
15
+ - 8c616f0: feat(mcp): add maxRetries option for failed mcp tool calls
16
+ - Updated dependencies [8c616f0]
17
+ - @ai-sdk/provider-utils@5.0.3
18
+
3
19
  ## 2.0.4
4
20
 
5
21
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -66,6 +66,7 @@ declare const JSONRPCMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
66
66
  }, z.core.$strip>;
67
67
  }, z.core.$strict>]>;
68
68
  type JSONRPCMessage = z.infer<typeof JSONRPCMessageSchema>;
69
+ declare function validateJSONRPCMessage(message: unknown): JSONRPCMessage;
69
70
 
70
71
  /**
71
72
  * OAuth 2.1 token response
@@ -600,6 +601,15 @@ interface MCPClientConfig {
600
601
  transport: MCPTransportConfig | MCPTransport;
601
602
  /** Optional callback for uncaught errors */
602
603
  onUncaughtError?: (error: unknown) => void;
604
+ /**
605
+ * Maximum number of retries for transient MCP tool call failures.
606
+ *
607
+ * Set to 0 to disable retries. Retries only apply to tools/call requests.
608
+ * JSON-RPC application errors, such as invalid params, are not retried.
609
+ *
610
+ * @default 0
611
+ */
612
+ maxRetries?: number;
603
613
  /**
604
614
  * Initialize result from a previous MCP session. When provided, the client
605
615
  * starts the transport and reuses this metadata without sending a new
@@ -752,4 +762,4 @@ declare function readMCPAppResource({ client, uri, options, }: {
752
762
  options?: RequestOptions;
753
763
  }): Promise<MCPAppResource>;
754
764
 
755
- export { type CallToolResult, type CompleteRequestParams, type CompleteResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type InitializeResult, 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 };
765
+ export { type CallToolResult, type CompleteRequestParams, type CompleteResult, type Configuration, type ElicitResult, ElicitResultSchema, type ElicitationRequest, ElicitationRequestSchema, type InitializeResult, 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, validateJSONRPCMessage };
package/dist/index.js CHANGED
@@ -1,50 +1,3 @@
1
- // src/tool/mcp-client.ts
2
- import {
3
- asSchema,
4
- dynamicTool,
5
- jsonSchema,
6
- safeParseJSON,
7
- safeValidateTypes,
8
- tool
9
- } from "@ai-sdk/provider-utils";
10
-
11
- // src/error/mcp-client-error.ts
12
- import { AISDKError } from "@ai-sdk/provider";
13
- var name = "AI_MCPClientError";
14
- var marker = `vercel.ai.error.${name}`;
15
- var symbol = Symbol.for(marker);
16
- var _a, _b;
17
- var MCPClientError = class extends (_b = AISDKError, _a = symbol, _b) {
18
- constructor({
19
- name: name3 = "MCPClientError",
20
- message,
21
- cause,
22
- data,
23
- code,
24
- statusCode,
25
- url,
26
- responseBody
27
- }) {
28
- super({ name: name3, message, cause });
29
- this[_a] = true;
30
- this.data = data;
31
- this.code = code;
32
- this.statusCode = statusCode;
33
- this.url = url;
34
- this.responseBody = responseBody;
35
- }
36
- static isInstance(error) {
37
- return AISDKError.hasMarker(error, marker);
38
- }
39
- };
40
-
41
- // src/tool/mcp-sse-transport.ts
42
- import {
43
- EventSourceParserStream,
44
- withUserAgentSuffix,
45
- getRuntimeEnvironmentUserAgent
46
- } from "@ai-sdk/provider-utils";
47
-
48
1
  // src/tool/json-rpc-message.ts
49
2
  import { parseJSON } from "@ai-sdk/provider-utils";
50
3
  import { z as z2 } from "zod/v4";
@@ -329,10 +282,61 @@ var JSONRPCMessageSchema = z2.union([
329
282
  JSONRPCResponseSchema,
330
283
  JSONRPCErrorSchema
331
284
  ]);
285
+ function validateJSONRPCMessage(message) {
286
+ return JSONRPCMessageSchema.parse(message);
287
+ }
332
288
  async function parseJSONRPCMessage(text) {
333
- return JSONRPCMessageSchema.parse(await parseJSON({ text }));
289
+ return validateJSONRPCMessage(await parseJSON({ text }));
334
290
  }
335
291
 
292
+ // src/tool/mcp-client.ts
293
+ import {
294
+ asSchema,
295
+ dynamicTool,
296
+ jsonSchema,
297
+ retryWithExponentialBackoff,
298
+ safeParseJSON,
299
+ safeValidateTypes,
300
+ tool
301
+ } from "@ai-sdk/provider-utils";
302
+
303
+ // src/error/mcp-client-error.ts
304
+ import { AISDKError } from "@ai-sdk/provider";
305
+ var name = "AI_MCPClientError";
306
+ var marker = `vercel.ai.error.${name}`;
307
+ var symbol = Symbol.for(marker);
308
+ var _a, _b;
309
+ var MCPClientError = class extends (_b = AISDKError, _a = symbol, _b) {
310
+ constructor({
311
+ name: name3 = "MCPClientError",
312
+ message,
313
+ cause,
314
+ data,
315
+ code,
316
+ statusCode,
317
+ url,
318
+ responseBody
319
+ }) {
320
+ super({ name: name3, message, cause });
321
+ this[_a] = true;
322
+ this.data = data;
323
+ this.code = code;
324
+ this.statusCode = statusCode;
325
+ this.url = url;
326
+ this.responseBody = responseBody;
327
+ }
328
+ static isInstance(error) {
329
+ return AISDKError.hasMarker(error, marker);
330
+ }
331
+ };
332
+
333
+ // src/tool/mcp-sse-transport.ts
334
+ import {
335
+ EventSourceParserStream,
336
+ withUserAgentSuffix,
337
+ getRuntimeEnvironmentUserAgent
338
+ } from "@ai-sdk/provider-utils";
339
+
336
340
  // src/version.ts
337
341
  var VERSION = typeof __PACKAGE_VERSION__ !== "undefined" ? __PACKAGE_VERSION__ : "0.0.0-test";
338
342
 
@@ -1720,9 +1724,7 @@ var HttpMCPTransport = class {
1720
1724
  const contentType = response.headers.get("content-type") || "";
1721
1725
  if (contentType.includes("application/json")) {
1722
1726
  const data = await response.json();
1723
- const messages = Array.isArray(data) ? data.map(
1724
- (message2) => JSONRPCMessageSchema.parse(message2)
1725
- ) : [JSONRPCMessageSchema.parse(data)];
1727
+ const messages = Array.isArray(data) ? data.map((message2) => validateJSONRPCMessage(message2)) : [validateJSONRPCMessage(data)];
1726
1728
  for (const jsonRpcMessage of messages) {
1727
1729
  (_d = this.onmessage) == null ? void 0 : _d.call(this, jsonRpcMessage);
1728
1730
  }
@@ -2042,6 +2044,55 @@ async function readMCPAppResource({
2042
2044
 
2043
2045
  // src/tool/mcp-client.ts
2044
2046
  var CLIENT_VERSION = "1.0.0";
2047
+ var DEFAULT_MAX_TOOL_CALL_RETRIES = 0;
2048
+ var DEFAULT_RETRY_ERROR_CODES = [
2049
+ "ConnectionRefused",
2050
+ "ConnectionClosed",
2051
+ "FailedToOpenSocket",
2052
+ "ECONNRESET",
2053
+ "ECONNREFUSED",
2054
+ "ETIMEDOUT",
2055
+ "EPIPE"
2056
+ ];
2057
+ function getErrorStatusCode(error) {
2058
+ if (error != null && typeof error === "object" && "statusCode" in error && typeof error.statusCode === "number") {
2059
+ return error.statusCode;
2060
+ }
2061
+ return void 0;
2062
+ }
2063
+ function getStringErrorCode(error) {
2064
+ if (error != null && typeof error === "object" && "code" in error && typeof error.code === "string") {
2065
+ return error.code;
2066
+ }
2067
+ return void 0;
2068
+ }
2069
+ function isRetryableMCPToolCallError(error) {
2070
+ const statusCode = getErrorStatusCode(error);
2071
+ if (statusCode != null) {
2072
+ return statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500;
2073
+ }
2074
+ if (MCPClientError.isInstance(error) && error.code != null) {
2075
+ return false;
2076
+ }
2077
+ const errorCode = getStringErrorCode(error);
2078
+ return errorCode != null && DEFAULT_RETRY_ERROR_CODES.includes(errorCode);
2079
+ }
2080
+ function prepareMaxRetries(maxRetries) {
2081
+ if (maxRetries == null) {
2082
+ return DEFAULT_MAX_TOOL_CALL_RETRIES;
2083
+ }
2084
+ if (!Number.isInteger(maxRetries)) {
2085
+ throw new MCPClientError({
2086
+ message: "maxRetries must be an integer"
2087
+ });
2088
+ }
2089
+ if (maxRetries < 0) {
2090
+ throw new MCPClientError({
2091
+ message: "maxRetries must be >= 0"
2092
+ });
2093
+ }
2094
+ return maxRetries;
2095
+ }
2045
2096
  function mcpToModelOutput({
2046
2097
  output
2047
2098
  }) {
@@ -2078,6 +2129,7 @@ var DefaultMCPClient = class {
2078
2129
  clientName = name3 != null ? name3 : "ai-sdk-mcp-client",
2079
2130
  version = CLIENT_VERSION,
2080
2131
  onUncaughtError,
2132
+ maxRetries,
2081
2133
  capabilities,
2082
2134
  initialInitializeResult
2083
2135
  }) {
@@ -2092,6 +2144,7 @@ var DefaultMCPClient = class {
2092
2144
  };
2093
2145
  this.isClosed = true;
2094
2146
  this.onUncaughtError = onUncaughtError;
2147
+ this.maxRetries = prepareMaxRetries(maxRetries);
2095
2148
  this.clientCapabilities = capabilities != null ? capabilities : {};
2096
2149
  this.initialInitializeResult = initialInitializeResult;
2097
2150
  if (isCustomMcpTransport(transportConfig)) {
@@ -2295,16 +2348,39 @@ var DefaultMCPClient = class {
2295
2348
  options
2296
2349
  });
2297
2350
  }
2351
+ async callToolWithRetry({
2352
+ options,
2353
+ execute
2354
+ }) {
2355
+ if (this.maxRetries === 0) {
2356
+ return execute();
2357
+ }
2358
+ return retryWithExponentialBackoff({
2359
+ maxRetries: this.maxRetries,
2360
+ abortSignal: options == null ? void 0 : options.signal,
2361
+ shouldRetry: isRetryableMCPToolCallError,
2362
+ createRetryError: ({ message, errors }) => new MCPClientError({
2363
+ message,
2364
+ cause: errors[errors.length - 1]
2365
+ })
2366
+ })(execute);
2367
+ }
2298
2368
  async callTool({
2299
2369
  name: name3,
2300
2370
  arguments: args = {},
2301
2371
  options
2302
2372
  }) {
2303
2373
  try {
2304
- return this.request({
2305
- request: { method: "tools/call", params: { name: name3, arguments: args } },
2306
- resultSchema: CallToolResultSchema,
2307
- options
2374
+ return this.callToolWithRetry({
2375
+ options,
2376
+ execute: () => this.request({
2377
+ request: {
2378
+ method: "tools/call",
2379
+ params: { name: name3, arguments: args }
2380
+ },
2381
+ resultSchema: CallToolResultSchema,
2382
+ options
2383
+ })
2308
2384
  });
2309
2385
  } catch (error) {
2310
2386
  throw error;
@@ -2678,6 +2754,7 @@ export {
2678
2754
  createMCPClient as experimental_createMCPClient,
2679
2755
  mcpAppClientCapabilities,
2680
2756
  readMCPAppResource,
2681
- splitMCPAppTools
2757
+ splitMCPAppTools,
2758
+ validateJSONRPCMessage
2682
2759
  };
2683
2760
  //# sourceMappingURL=index.js.map