@ai-sdk/mcp 2.0.4 → 2.0.5

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,13 @@
1
1
  # @ai-sdk/mcp
2
2
 
3
+ ## 2.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 8c616f0: feat(mcp): add maxRetries option for failed mcp tool calls
8
+ - Updated dependencies [8c616f0]
9
+ - @ai-sdk/provider-utils@5.0.3
10
+
3
11
  ## 2.0.4
4
12
 
5
13
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -600,6 +600,15 @@ interface MCPClientConfig {
600
600
  transport: MCPTransportConfig | MCPTransport;
601
601
  /** Optional callback for uncaught errors */
602
602
  onUncaughtError?: (error: unknown) => void;
603
+ /**
604
+ * Maximum number of retries for transient MCP tool call failures.
605
+ *
606
+ * Set to 0 to disable retries. Retries only apply to tools/call requests.
607
+ * JSON-RPC application errors, such as invalid params, are not retried.
608
+ *
609
+ * @default 0
610
+ */
611
+ maxRetries?: number;
603
612
  /**
604
613
  * Initialize result from a previous MCP session. When provided, the client
605
614
  * starts the transport and reuses this metadata without sending a new
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  asSchema,
4
4
  dynamicTool,
5
5
  jsonSchema,
6
+ retryWithExponentialBackoff,
6
7
  safeParseJSON,
7
8
  safeValidateTypes,
8
9
  tool
@@ -2042,6 +2043,55 @@ async function readMCPAppResource({
2042
2043
 
2043
2044
  // src/tool/mcp-client.ts
2044
2045
  var CLIENT_VERSION = "1.0.0";
2046
+ var DEFAULT_MAX_TOOL_CALL_RETRIES = 0;
2047
+ var DEFAULT_RETRY_ERROR_CODES = [
2048
+ "ConnectionRefused",
2049
+ "ConnectionClosed",
2050
+ "FailedToOpenSocket",
2051
+ "ECONNRESET",
2052
+ "ECONNREFUSED",
2053
+ "ETIMEDOUT",
2054
+ "EPIPE"
2055
+ ];
2056
+ function getErrorStatusCode(error) {
2057
+ if (error != null && typeof error === "object" && "statusCode" in error && typeof error.statusCode === "number") {
2058
+ return error.statusCode;
2059
+ }
2060
+ return void 0;
2061
+ }
2062
+ function getStringErrorCode(error) {
2063
+ if (error != null && typeof error === "object" && "code" in error && typeof error.code === "string") {
2064
+ return error.code;
2065
+ }
2066
+ return void 0;
2067
+ }
2068
+ function isRetryableMCPToolCallError(error) {
2069
+ const statusCode = getErrorStatusCode(error);
2070
+ if (statusCode != null) {
2071
+ return statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500;
2072
+ }
2073
+ if (MCPClientError.isInstance(error) && error.code != null) {
2074
+ return false;
2075
+ }
2076
+ const errorCode = getStringErrorCode(error);
2077
+ return errorCode != null && DEFAULT_RETRY_ERROR_CODES.includes(errorCode);
2078
+ }
2079
+ function prepareMaxRetries(maxRetries) {
2080
+ if (maxRetries == null) {
2081
+ return DEFAULT_MAX_TOOL_CALL_RETRIES;
2082
+ }
2083
+ if (!Number.isInteger(maxRetries)) {
2084
+ throw new MCPClientError({
2085
+ message: "maxRetries must be an integer"
2086
+ });
2087
+ }
2088
+ if (maxRetries < 0) {
2089
+ throw new MCPClientError({
2090
+ message: "maxRetries must be >= 0"
2091
+ });
2092
+ }
2093
+ return maxRetries;
2094
+ }
2045
2095
  function mcpToModelOutput({
2046
2096
  output
2047
2097
  }) {
@@ -2078,6 +2128,7 @@ var DefaultMCPClient = class {
2078
2128
  clientName = name3 != null ? name3 : "ai-sdk-mcp-client",
2079
2129
  version = CLIENT_VERSION,
2080
2130
  onUncaughtError,
2131
+ maxRetries,
2081
2132
  capabilities,
2082
2133
  initialInitializeResult
2083
2134
  }) {
@@ -2092,6 +2143,7 @@ var DefaultMCPClient = class {
2092
2143
  };
2093
2144
  this.isClosed = true;
2094
2145
  this.onUncaughtError = onUncaughtError;
2146
+ this.maxRetries = prepareMaxRetries(maxRetries);
2095
2147
  this.clientCapabilities = capabilities != null ? capabilities : {};
2096
2148
  this.initialInitializeResult = initialInitializeResult;
2097
2149
  if (isCustomMcpTransport(transportConfig)) {
@@ -2295,16 +2347,39 @@ var DefaultMCPClient = class {
2295
2347
  options
2296
2348
  });
2297
2349
  }
2350
+ async callToolWithRetry({
2351
+ options,
2352
+ execute
2353
+ }) {
2354
+ if (this.maxRetries === 0) {
2355
+ return execute();
2356
+ }
2357
+ return retryWithExponentialBackoff({
2358
+ maxRetries: this.maxRetries,
2359
+ abortSignal: options == null ? void 0 : options.signal,
2360
+ shouldRetry: isRetryableMCPToolCallError,
2361
+ createRetryError: ({ message, errors }) => new MCPClientError({
2362
+ message,
2363
+ cause: errors[errors.length - 1]
2364
+ })
2365
+ })(execute);
2366
+ }
2298
2367
  async callTool({
2299
2368
  name: name3,
2300
2369
  arguments: args = {},
2301
2370
  options
2302
2371
  }) {
2303
2372
  try {
2304
- return this.request({
2305
- request: { method: "tools/call", params: { name: name3, arguments: args } },
2306
- resultSchema: CallToolResultSchema,
2307
- options
2373
+ return this.callToolWithRetry({
2374
+ options,
2375
+ execute: () => this.request({
2376
+ request: {
2377
+ method: "tools/call",
2378
+ params: { name: name3, arguments: args }
2379
+ },
2380
+ resultSchema: CallToolResultSchema,
2381
+ options
2382
+ })
2308
2383
  });
2309
2384
  } catch (error) {
2310
2385
  throw error;