@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 +16 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +133 -56
- package/dist/index.js.map +1 -1
- package/dist/mcp-stdio/index.js +4 -1
- package/dist/mcp-stdio/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/tool/json-rpc-message.ts +5 -1
- package/src/tool/mcp-client.ts +122 -3
- package/src/tool/mcp-http-transport.ts +3 -5
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
|
|
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.
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
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
|