@ai-sdk/mcp 2.0.32 → 2.0.33
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 +8 -0
- package/README.md +15 -0
- package/dist/index.d.ts +54 -3
- package/dist/index.js +421 -48
- package/dist/index.js.map +1 -1
- package/dist/mcp-stdio/index.d.ts +19 -1
- package/dist/mcp-stdio/index.js +15 -5
- package/dist/mcp-stdio/index.js.map +1 -1
- package/package.json +3 -3
- package/src/tool/json-rpc-message.ts +1 -1
- package/src/tool/mcp-client.ts +251 -22
- package/src/tool/mcp-http-headers.ts +161 -0
- package/src/tool/mcp-http-transport.ts +99 -10
- package/src/tool/mcp-sse-transport.ts +3 -2
- package/src/tool/mcp-stdio/mcp-stdio-transport.ts +1 -0
- package/src/tool/mcp-transport.ts +25 -1
- package/src/tool/mock-mcp-transport.ts +2 -2
- package/src/tool/oauth-types.ts +9 -0
- package/src/tool/oauth.ts +75 -1
- package/src/tool/types.ts +19 -8
package/dist/index.js
CHANGED
|
@@ -4,9 +4,11 @@ import { z as z2 } from "zod/v4";
|
|
|
4
4
|
|
|
5
5
|
// src/tool/types.ts
|
|
6
6
|
import { z } from "zod/v4";
|
|
7
|
-
var LATEST_PROTOCOL_VERSION = "
|
|
7
|
+
var LATEST_PROTOCOL_VERSION = "2026-07-28";
|
|
8
|
+
var LATEST_LEGACY_PROTOCOL_VERSION = "2025-11-25";
|
|
8
9
|
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
9
10
|
LATEST_PROTOCOL_VERSION,
|
|
11
|
+
LATEST_LEGACY_PROTOCOL_VERSION,
|
|
10
12
|
"2025-06-18",
|
|
11
13
|
"2025-03-26",
|
|
12
14
|
"2024-11-05"
|
|
@@ -20,7 +22,9 @@ var ClientOrServerImplementationSchema = z.looseObject({
|
|
|
20
22
|
var BaseParamsSchema = z.looseObject({
|
|
21
23
|
_meta: z.optional(z.object({}).loose())
|
|
22
24
|
});
|
|
23
|
-
var ResultSchema = BaseParamsSchema
|
|
25
|
+
var ResultSchema = BaseParamsSchema.extend({
|
|
26
|
+
resultType: z.optional(z.string())
|
|
27
|
+
});
|
|
24
28
|
var RequestSchema = z.object({
|
|
25
29
|
method: z.string(),
|
|
26
30
|
params: z.optional(BaseParamsSchema)
|
|
@@ -53,6 +57,13 @@ var ServerCapabilitiesSchema = z.looseObject({
|
|
|
53
57
|
var ClientCapabilitiesSchema = z.object({
|
|
54
58
|
elicitation: z.optional(ElicitationCapabilitySchema)
|
|
55
59
|
}).loose();
|
|
60
|
+
var DiscoverResultSchema = ResultSchema.extend({
|
|
61
|
+
supportedVersions: z.array(z.string()),
|
|
62
|
+
capabilities: ServerCapabilitiesSchema,
|
|
63
|
+
instructions: z.optional(z.string()),
|
|
64
|
+
ttlMs: z.optional(z.number()),
|
|
65
|
+
cacheScope: z.optional(z.union([z.literal("public"), z.literal("private")]))
|
|
66
|
+
});
|
|
56
67
|
var InitializeResultSchema = ResultSchema.extend({
|
|
57
68
|
protocolVersion: z.string(),
|
|
58
69
|
capabilities: ServerCapabilitiesSchema,
|
|
@@ -69,10 +80,10 @@ var ToolSchema = z.object({
|
|
|
69
80
|
*/
|
|
70
81
|
title: z.optional(z.string()),
|
|
71
82
|
description: z.optional(z.string()),
|
|
72
|
-
inputSchema: z.
|
|
73
|
-
type: z.
|
|
83
|
+
inputSchema: z.looseObject({
|
|
84
|
+
type: z.optional(z.unknown()),
|
|
74
85
|
properties: z.optional(z.object({}).loose())
|
|
75
|
-
})
|
|
86
|
+
}),
|
|
76
87
|
/**
|
|
77
88
|
* @see https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
|
|
78
89
|
*/
|
|
@@ -261,7 +272,7 @@ var JSONRPCResponseSchema = z2.object({
|
|
|
261
272
|
}).strict();
|
|
262
273
|
var JSONRPCErrorSchema = z2.object({
|
|
263
274
|
jsonrpc: z2.literal(JSONRPC_VERSION),
|
|
264
|
-
id: z2.union([z2.string(), z2.number().int()]),
|
|
275
|
+
id: z2.optional(z2.union([z2.string(), z2.number().int()])),
|
|
265
276
|
error: z2.object({
|
|
266
277
|
code: z2.number().int(),
|
|
267
278
|
message: z2.string(),
|
|
@@ -369,6 +380,7 @@ var OAuthTokensSchema = z3.object({
|
|
|
369
380
|
expires_in: z3.number().optional(),
|
|
370
381
|
scope: z3.string().optional(),
|
|
371
382
|
refresh_token: z3.string().optional(),
|
|
383
|
+
issuer: SafeUrlSchema.optional(),
|
|
372
384
|
authorization_server: SafeUrlSchema.optional(),
|
|
373
385
|
token_endpoint: SafeUrlSchema.optional()
|
|
374
386
|
}).strip();
|
|
@@ -393,6 +405,8 @@ var OAuthMetadataSchema = z3.looseObject({
|
|
|
393
405
|
authorization_endpoint: SafeUrlSchema,
|
|
394
406
|
token_endpoint: SafeUrlSchema,
|
|
395
407
|
registration_endpoint: SafeUrlSchema.optional(),
|
|
408
|
+
authorization_response_iss_parameter_supported: z3.boolean().optional(),
|
|
409
|
+
client_id_metadata_document_supported: z3.boolean().optional(),
|
|
396
410
|
scopes_supported: z3.array(z3.string()).optional(),
|
|
397
411
|
response_types_supported: z3.array(z3.string()),
|
|
398
412
|
grant_types_supported: z3.array(z3.string()).optional(),
|
|
@@ -407,6 +421,8 @@ var OpenIdProviderMetadataSchema = z3.looseObject({
|
|
|
407
421
|
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
408
422
|
jwks_uri: SafeUrlSchema,
|
|
409
423
|
registration_endpoint: SafeUrlSchema.optional(),
|
|
424
|
+
authorization_response_iss_parameter_supported: z3.boolean().optional(),
|
|
425
|
+
client_id_metadata_document_supported: z3.boolean().optional(),
|
|
410
426
|
scopes_supported: z3.array(z3.string()).optional(),
|
|
411
427
|
response_types_supported: z3.array(z3.string()),
|
|
412
428
|
grant_types_supported: z3.array(z3.string()).optional(),
|
|
@@ -425,11 +441,13 @@ var OAuthClientInformationSchema = z3.object({
|
|
|
425
441
|
client_secret: z3.string().optional(),
|
|
426
442
|
client_id_issued_at: z3.number().optional(),
|
|
427
443
|
client_secret_expires_at: z3.number().optional(),
|
|
444
|
+
issuer: SafeUrlSchema.optional(),
|
|
428
445
|
authorization_server: SafeUrlSchema.optional(),
|
|
429
446
|
token_endpoint: SafeUrlSchema.optional()
|
|
430
447
|
}).strip();
|
|
431
448
|
var OAuthClientMetadataSchema = z3.object({
|
|
432
449
|
redirect_uris: z3.array(SafeUrlSchema),
|
|
450
|
+
application_type: z3.union([z3.literal("native"), z3.literal("web")]).optional(),
|
|
433
451
|
token_endpoint_auth_method: z3.string().optional(),
|
|
434
452
|
grant_types: z3.array(z3.string()).optional(),
|
|
435
453
|
response_types: z3.array(z3.string()).optional(),
|
|
@@ -534,8 +552,20 @@ var UnauthorizedError = class extends Error {
|
|
|
534
552
|
function normalizeUrl(url) {
|
|
535
553
|
return new URL(url).href;
|
|
536
554
|
}
|
|
555
|
+
function validateAuthorizationResponseIssuer({
|
|
556
|
+
callbackIssuer,
|
|
557
|
+
expectedIssuer
|
|
558
|
+
}) {
|
|
559
|
+
if (callbackIssuer != null && callbackIssuer !== expectedIssuer) {
|
|
560
|
+
throw new MCPClientOAuthError({
|
|
561
|
+
message: `OAuth authorization response issuer ${callbackIssuer} does not match expected issuer ${expectedIssuer}`
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
537
565
|
function createAuthorizationServerInformation(authorizationServerUrl, metadata) {
|
|
566
|
+
var _a3;
|
|
538
567
|
return {
|
|
568
|
+
issuer: (_a3 = metadata == null ? void 0 : metadata.issuer) != null ? _a3 : String(authorizationServerUrl),
|
|
539
569
|
authorizationServerUrl: normalizeUrl(authorizationServerUrl),
|
|
540
570
|
tokenEndpoint: normalizeUrl(
|
|
541
571
|
(metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl)
|
|
@@ -545,6 +575,7 @@ function createAuthorizationServerInformation(authorizationServerUrl, metadata)
|
|
|
545
575
|
function addAuthorizationServerInformationToTokens(tokens, authorizationServerInformation) {
|
|
546
576
|
return {
|
|
547
577
|
...tokens,
|
|
578
|
+
issuer: authorizationServerInformation.issuer,
|
|
548
579
|
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
549
580
|
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
550
581
|
};
|
|
@@ -552,6 +583,7 @@ function addAuthorizationServerInformationToTokens(tokens, authorizationServerIn
|
|
|
552
583
|
function addAuthorizationServerInformationToClientInformation(clientInformation, authorizationServerInformation) {
|
|
553
584
|
return {
|
|
554
585
|
...clientInformation,
|
|
586
|
+
issuer: authorizationServerInformation.issuer,
|
|
555
587
|
authorization_server: authorizationServerInformation.authorizationServerUrl,
|
|
556
588
|
token_endpoint: authorizationServerInformation.tokenEndpoint
|
|
557
589
|
};
|
|
@@ -561,6 +593,7 @@ function getAuthorizationServerInformationFromCredentials(credentials) {
|
|
|
561
593
|
return void 0;
|
|
562
594
|
}
|
|
563
595
|
return {
|
|
596
|
+
issuer: credentials.issuer,
|
|
564
597
|
authorizationServerUrl: normalizeUrl(credentials.authorization_server),
|
|
565
598
|
tokenEndpoint: normalizeUrl(credentials.token_endpoint)
|
|
566
599
|
};
|
|
@@ -578,6 +611,7 @@ async function getStoredAuthorizationServerInformation({
|
|
|
578
611
|
const providerAuthorizationServerInformation = await ((_a3 = provider.authorizationServerInformation) == null ? void 0 : _a3.call(provider));
|
|
579
612
|
if (providerAuthorizationServerInformation) {
|
|
580
613
|
return {
|
|
614
|
+
issuer: providerAuthorizationServerInformation.issuer,
|
|
581
615
|
authorizationServerUrl: normalizeUrl(
|
|
582
616
|
providerAuthorizationServerInformation.authorizationServerUrl
|
|
583
617
|
),
|
|
@@ -625,7 +659,7 @@ function assertAuthorizationServerInformationMatches({
|
|
|
625
659
|
storedAuthorizationServerInformation,
|
|
626
660
|
currentAuthorizationServerInformation
|
|
627
661
|
}) {
|
|
628
|
-
if (storedAuthorizationServerInformation.authorizationServerUrl !== currentAuthorizationServerInformation.authorizationServerUrl || storedAuthorizationServerInformation.tokenEndpoint !== currentAuthorizationServerInformation.tokenEndpoint) {
|
|
662
|
+
if (storedAuthorizationServerInformation.issuer != null && currentAuthorizationServerInformation.issuer != null && storedAuthorizationServerInformation.issuer !== currentAuthorizationServerInformation.issuer || storedAuthorizationServerInformation.authorizationServerUrl !== currentAuthorizationServerInformation.authorizationServerUrl || storedAuthorizationServerInformation.tokenEndpoint !== currentAuthorizationServerInformation.tokenEndpoint) {
|
|
629
663
|
throw new MCPClientOAuthError({
|
|
630
664
|
message: "OAuth authorization server metadata does not match the metadata that issued the stored credentials"
|
|
631
665
|
});
|
|
@@ -1074,6 +1108,7 @@ async function registerClient(authorizationServerUrl, {
|
|
|
1074
1108
|
clientMetadata,
|
|
1075
1109
|
fetchFn
|
|
1076
1110
|
}) {
|
|
1111
|
+
var _a3;
|
|
1077
1112
|
let registrationUrl;
|
|
1078
1113
|
if (metadata) {
|
|
1079
1114
|
if (!metadata.registration_endpoint) {
|
|
@@ -1085,18 +1120,29 @@ async function registerClient(authorizationServerUrl, {
|
|
|
1085
1120
|
} else {
|
|
1086
1121
|
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
1087
1122
|
}
|
|
1123
|
+
const applicationType = (_a3 = clientMetadata.application_type) != null ? _a3 : inferOAuthApplicationType(clientMetadata.redirect_uris);
|
|
1088
1124
|
const response = await (fetchFn != null ? fetchFn : fetch)(registrationUrl, {
|
|
1089
1125
|
method: "POST",
|
|
1090
1126
|
headers: {
|
|
1091
1127
|
"Content-Type": "application/json"
|
|
1092
1128
|
},
|
|
1093
|
-
body: JSON.stringify(
|
|
1129
|
+
body: JSON.stringify({
|
|
1130
|
+
...clientMetadata,
|
|
1131
|
+
application_type: applicationType
|
|
1132
|
+
})
|
|
1094
1133
|
});
|
|
1095
1134
|
if (!response.ok) {
|
|
1096
1135
|
throw await parseErrorResponse(response);
|
|
1097
1136
|
}
|
|
1098
1137
|
return OAuthClientInformationFullSchema.parse(await response.json());
|
|
1099
1138
|
}
|
|
1139
|
+
function inferOAuthApplicationType(redirectUris) {
|
|
1140
|
+
const isNativeRedirectUri = (redirectUri) => {
|
|
1141
|
+
const url = new URL(redirectUri);
|
|
1142
|
+
return (url.protocol === "http:" || url.protocol === "https:") && (url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1" || url.hostname === "[::1]") || url.protocol !== "http:" && url.protocol !== "https:";
|
|
1143
|
+
};
|
|
1144
|
+
return redirectUris.every(isNativeRedirectUri) ? "native" : "web";
|
|
1145
|
+
}
|
|
1100
1146
|
async function auth(provider, options) {
|
|
1101
1147
|
var _a3, _b3;
|
|
1102
1148
|
try {
|
|
@@ -1137,11 +1183,12 @@ async function authInternal(provider, {
|
|
|
1137
1183
|
serverUrl,
|
|
1138
1184
|
authorizationCode,
|
|
1139
1185
|
callbackState,
|
|
1186
|
+
callbackIssuer,
|
|
1140
1187
|
scope,
|
|
1141
1188
|
resourceMetadataUrl,
|
|
1142
1189
|
fetchFn
|
|
1143
1190
|
}) {
|
|
1144
|
-
var _a3, _b3;
|
|
1191
|
+
var _a3, _b3, _c, _d;
|
|
1145
1192
|
let resourceMetadata;
|
|
1146
1193
|
let authorizationServerUrl;
|
|
1147
1194
|
assertResourceMetadataUrlSameOrigin(serverUrl, resourceMetadataUrl);
|
|
@@ -1177,6 +1224,18 @@ async function authInternal(provider, {
|
|
|
1177
1224
|
);
|
|
1178
1225
|
const currentAuthorizationServerInformation = createAuthorizationServerInformation(authorizationServerUrl, metadata);
|
|
1179
1226
|
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
1227
|
+
if ((clientInformation == null ? void 0 : clientInformation.issuer) != null) {
|
|
1228
|
+
const storedAuthorizationServerInformation = await getStoredAuthorizationServerInformation({
|
|
1229
|
+
provider,
|
|
1230
|
+
clientInformation
|
|
1231
|
+
});
|
|
1232
|
+
if (storedAuthorizationServerInformation) {
|
|
1233
|
+
assertAuthorizationServerInformationMatches({
|
|
1234
|
+
storedAuthorizationServerInformation,
|
|
1235
|
+
currentAuthorizationServerInformation
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1180
1239
|
if (!clientInformation) {
|
|
1181
1240
|
if (authorizationCode !== void 0) {
|
|
1182
1241
|
throw new Error(
|
|
@@ -1217,6 +1276,10 @@ async function authInternal(provider, {
|
|
|
1217
1276
|
message: "Stored OAuth authorization server metadata is required when exchanging an authorization code"
|
|
1218
1277
|
});
|
|
1219
1278
|
}
|
|
1279
|
+
validateAuthorizationResponseIssuer({
|
|
1280
|
+
callbackIssuer,
|
|
1281
|
+
expectedIssuer: (_c = (_b3 = storedAuthorizationServerInformation.issuer) != null ? _b3 : metadata == null ? void 0 : metadata.issuer) != null ? _c : String(authorizationServerUrl)
|
|
1282
|
+
});
|
|
1220
1283
|
assertAuthorizationServerInformationMatches({
|
|
1221
1284
|
storedAuthorizationServerInformation,
|
|
1222
1285
|
currentAuthorizationServerInformation
|
|
@@ -1253,7 +1316,7 @@ async function authInternal(provider, {
|
|
|
1253
1316
|
currentAuthorizationServerInformation
|
|
1254
1317
|
});
|
|
1255
1318
|
} else {
|
|
1256
|
-
await ((
|
|
1319
|
+
await ((_d = provider.invalidateCredentials) == null ? void 0 : _d.call(provider, "tokens"));
|
|
1257
1320
|
}
|
|
1258
1321
|
try {
|
|
1259
1322
|
if (storedAuthorizationServerInformation) {
|
|
@@ -1344,7 +1407,7 @@ var SseMCPTransport = class {
|
|
|
1344
1407
|
const headers = {
|
|
1345
1408
|
...this.headers,
|
|
1346
1409
|
...base,
|
|
1347
|
-
"mcp-protocol-version": (_a3 = this.protocolVersion) != null ? _a3 :
|
|
1410
|
+
"mcp-protocol-version": (_a3 = this.protocolVersion) != null ? _a3 : LATEST_LEGACY_PROTOCOL_VERSION
|
|
1348
1411
|
};
|
|
1349
1412
|
if (this.authProvider) {
|
|
1350
1413
|
const tokens = await this.authProvider.tokens();
|
|
@@ -1557,6 +1620,107 @@ import {
|
|
|
1557
1620
|
withUserAgentSuffix as withUserAgentSuffix2,
|
|
1558
1621
|
getRuntimeEnvironmentUserAgent as getRuntimeEnvironmentUserAgent2
|
|
1559
1622
|
} from "@ai-sdk/provider-utils";
|
|
1623
|
+
|
|
1624
|
+
// src/tool/mcp-http-headers.ts
|
|
1625
|
+
import { convertUint8ArrayToBase64, isRecord } from "@ai-sdk/provider-utils";
|
|
1626
|
+
var HTTP_TOKEN_PATTERN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
1627
|
+
var BASE64_SENTINEL_PATTERN = /^=\?base64\?.*\?=$/;
|
|
1628
|
+
function encodeMCPHeaderValue(value) {
|
|
1629
|
+
const isPlainAscii = [...value].every((character) => {
|
|
1630
|
+
const code = character.charCodeAt(0);
|
|
1631
|
+
return code === 9 || code >= 32 && code <= 126;
|
|
1632
|
+
});
|
|
1633
|
+
if (isPlainAscii && value.trim() === value && !BASE64_SENTINEL_PATTERN.test(value)) {
|
|
1634
|
+
return value;
|
|
1635
|
+
}
|
|
1636
|
+
return `=?base64?${convertUint8ArrayToBase64(new TextEncoder().encode(value))}?=`;
|
|
1637
|
+
}
|
|
1638
|
+
function getMCPToolHeaderBindings(inputSchema) {
|
|
1639
|
+
if (!isRecord(inputSchema)) {
|
|
1640
|
+
return {
|
|
1641
|
+
success: false,
|
|
1642
|
+
error: "inputSchema must be a JSON Schema object"
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
const bindings = [];
|
|
1646
|
+
const headerNames = /* @__PURE__ */ new Set();
|
|
1647
|
+
let error;
|
|
1648
|
+
const visit = (value, path, staticallyReachable) => {
|
|
1649
|
+
if (error != null || !isRecord(value)) {
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
if ("x-mcp-header" in value) {
|
|
1653
|
+
if (!staticallyReachable || path.length === 0) {
|
|
1654
|
+
error = "x-mcp-header is not on a statically reachable property";
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
const headerName = value["x-mcp-header"];
|
|
1658
|
+
if (typeof headerName !== "string" || !HTTP_TOKEN_PATTERN.test(headerName)) {
|
|
1659
|
+
error = "x-mcp-header must be a non-empty HTTP token";
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const normalizedHeaderName = headerName.toLowerCase();
|
|
1663
|
+
if (headerNames.has(normalizedHeaderName)) {
|
|
1664
|
+
error = `x-mcp-header value "${headerName}" is not unique`;
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
const valueType = value.type;
|
|
1668
|
+
if (valueType !== "boolean" && valueType !== "integer" && valueType !== "string") {
|
|
1669
|
+
error = "x-mcp-header can only annotate boolean, integer, or string properties";
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
headerNames.add(normalizedHeaderName);
|
|
1673
|
+
bindings.push({ headerName, path, valueType });
|
|
1674
|
+
}
|
|
1675
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1676
|
+
if (key === "x-mcp-header") {
|
|
1677
|
+
continue;
|
|
1678
|
+
}
|
|
1679
|
+
if (key === "properties" && isRecord(child)) {
|
|
1680
|
+
for (const [propertyName, propertySchema] of Object.entries(child)) {
|
|
1681
|
+
visit(propertySchema, [...path, propertyName], staticallyReachable);
|
|
1682
|
+
}
|
|
1683
|
+
} else {
|
|
1684
|
+
visit(child, path, false);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
visit(inputSchema, [], true);
|
|
1689
|
+
return error == null ? { success: true, bindings } : { success: false, error };
|
|
1690
|
+
}
|
|
1691
|
+
function getValueAtPath(value, path) {
|
|
1692
|
+
let current = value;
|
|
1693
|
+
for (const segment of path) {
|
|
1694
|
+
if (!isRecord(current)) {
|
|
1695
|
+
return void 0;
|
|
1696
|
+
}
|
|
1697
|
+
current = current[segment];
|
|
1698
|
+
}
|
|
1699
|
+
return current;
|
|
1700
|
+
}
|
|
1701
|
+
function createMCPToolHeaders({
|
|
1702
|
+
bindings,
|
|
1703
|
+
args
|
|
1704
|
+
}) {
|
|
1705
|
+
const headers = {};
|
|
1706
|
+
for (const binding of bindings) {
|
|
1707
|
+
const value = getValueAtPath(args, binding.path);
|
|
1708
|
+
if (value == null) {
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
if (binding.valueType === "string" && typeof value !== "string" || binding.valueType === "boolean" && typeof value !== "boolean" || binding.valueType === "integer" && !Number.isSafeInteger(value)) {
|
|
1712
|
+
throw new TypeError(
|
|
1713
|
+
`Tool argument "${binding.path.join(".")}" does not match its x-mcp-header type`
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
headers[`Mcp-Param-${binding.headerName}`] = encodeMCPHeaderValue(
|
|
1717
|
+
String(value)
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
return headers;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// src/tool/mcp-http-transport.ts
|
|
1560
1724
|
function isMessageEvent2(event) {
|
|
1561
1725
|
return event === void 0 || event === "message";
|
|
1562
1726
|
}
|
|
@@ -1573,6 +1737,8 @@ var HttpMCPTransport = class {
|
|
|
1573
1737
|
terminateSessionOnClose = true,
|
|
1574
1738
|
fetch: fetchFn
|
|
1575
1739
|
}) {
|
|
1740
|
+
this.supportsProtocolVersionDiscovery = true;
|
|
1741
|
+
this.supportsMcpToolParameterHeaders = true;
|
|
1576
1742
|
this.inboundReconnectAttempts = 0;
|
|
1577
1743
|
this.reconnectionOptions = {
|
|
1578
1744
|
initialReconnectionDelay: 1e3,
|
|
@@ -1585,14 +1751,30 @@ var HttpMCPTransport = class {
|
|
|
1585
1751
|
this.authProvider = authProvider;
|
|
1586
1752
|
this.redirectMode = redirect;
|
|
1587
1753
|
this.sessionId = initialSessionId;
|
|
1588
|
-
this.protocolVersion = initialProtocolVersion;
|
|
1754
|
+
this.protocolVersion = initialProtocolVersion != null ? initialProtocolVersion : LATEST_LEGACY_PROTOCOL_VERSION;
|
|
1589
1755
|
this.onSessionIdChange = onSessionIdChange;
|
|
1590
1756
|
this.onSessionExpired = onSessionExpired;
|
|
1591
1757
|
this.terminateSessionOnClose = terminateSessionOnClose;
|
|
1592
1758
|
this.fetchFn = fetchFn != null ? fetchFn : globalThis.fetch;
|
|
1593
1759
|
}
|
|
1594
1760
|
setProtocolVersion(version) {
|
|
1761
|
+
var _a3;
|
|
1595
1762
|
this.protocolVersion = version;
|
|
1763
|
+
if (!this.abortController) {
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
if (this.isModernProtocol()) {
|
|
1767
|
+
(_a3 = this.inboundSseConnection) == null ? void 0 : _a3.close();
|
|
1768
|
+
this.inboundSseConnection = void 0;
|
|
1769
|
+
return;
|
|
1770
|
+
}
|
|
1771
|
+
if (!this.inboundSseConnection) {
|
|
1772
|
+
this.startInboundSse();
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
isModernProtocol() {
|
|
1776
|
+
var _a3;
|
|
1777
|
+
return ((_a3 = this.protocolVersion) != null ? _a3 : LATEST_PROTOCOL_VERSION) === LATEST_PROTOCOL_VERSION;
|
|
1596
1778
|
}
|
|
1597
1779
|
async commonHeaders({
|
|
1598
1780
|
base,
|
|
@@ -1602,9 +1784,9 @@ var HttpMCPTransport = class {
|
|
|
1602
1784
|
const headers = {
|
|
1603
1785
|
...this.headers,
|
|
1604
1786
|
...base,
|
|
1605
|
-
"mcp-protocol-version": (_a3 = this.protocolVersion) != null ? _a3 :
|
|
1787
|
+
"mcp-protocol-version": (_a3 = this.protocolVersion) != null ? _a3 : LATEST_LEGACY_PROTOCOL_VERSION
|
|
1606
1788
|
};
|
|
1607
|
-
if (includeSessionId && this.sessionId) {
|
|
1789
|
+
if (!this.isModernProtocol() && includeSessionId && this.sessionId) {
|
|
1608
1790
|
headers["mcp-session-id"] = this.sessionId;
|
|
1609
1791
|
}
|
|
1610
1792
|
if (this.authProvider) {
|
|
@@ -1628,6 +1810,9 @@ var HttpMCPTransport = class {
|
|
|
1628
1810
|
(_a3 = this.onSessionIdChange) == null ? void 0 : _a3.call(this, sessionId);
|
|
1629
1811
|
}
|
|
1630
1812
|
applySessionIdFromResponse(response) {
|
|
1813
|
+
if (this.isModernProtocol()) {
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1631
1816
|
const sessionId = response.headers.get("mcp-session-id");
|
|
1632
1817
|
if (sessionId) {
|
|
1633
1818
|
this.setSessionId(sessionId);
|
|
@@ -1666,14 +1851,16 @@ var HttpMCPTransport = class {
|
|
|
1666
1851
|
});
|
|
1667
1852
|
}
|
|
1668
1853
|
this.abortController = new AbortController();
|
|
1669
|
-
this.
|
|
1854
|
+
if (this.protocolVersion != null && this.protocolVersion !== LATEST_PROTOCOL_VERSION) {
|
|
1855
|
+
this.startInboundSse();
|
|
1856
|
+
}
|
|
1670
1857
|
}
|
|
1671
1858
|
async close(options) {
|
|
1672
1859
|
var _a3, _b3, _c, _d, _e;
|
|
1673
1860
|
(_a3 = this.inboundSseConnection) == null ? void 0 : _a3.close();
|
|
1674
1861
|
(_b3 = this.abortController) == null ? void 0 : _b3.abort();
|
|
1675
1862
|
try {
|
|
1676
|
-
if (this.sessionId && this.terminateSessionOnClose && this.abortController) {
|
|
1863
|
+
if (!this.isModernProtocol() && this.sessionId && this.terminateSessionOnClose && this.abortController) {
|
|
1677
1864
|
(_c = options == null ? void 0 : options.signal) == null ? void 0 : _c.throwIfAborted();
|
|
1678
1865
|
const headers = await this.commonHeaders({ base: {} });
|
|
1679
1866
|
(_d = options == null ? void 0 : options.signal) == null ? void 0 : _d.throwIfAborted();
|
|
@@ -1694,14 +1881,16 @@ var HttpMCPTransport = class {
|
|
|
1694
1881
|
const transportSignal = (_b3 = this.abortController) == null ? void 0 : _b3.signal;
|
|
1695
1882
|
const requestSignal = (options == null ? void 0 : options.signal) == null ? transportSignal : transportSignal == null ? options.signal : AbortSignal.any([transportSignal, options.signal]);
|
|
1696
1883
|
const attempt = async (triedAuth = false) => {
|
|
1697
|
-
var _a4, _b4, _c, _d, _e, _f, _g;
|
|
1884
|
+
var _a4, _b4, _c, _d, _e, _f, _g, _h;
|
|
1698
1885
|
try {
|
|
1699
1886
|
const isInitializeRequest = "method" in message && message.method === "initialize";
|
|
1700
1887
|
const sessionIdForRequest = isInitializeRequest ? void 0 : this.sessionId;
|
|
1701
1888
|
const headers = await this.commonHeaders({
|
|
1702
1889
|
base: {
|
|
1703
1890
|
"Content-Type": "application/json",
|
|
1704
|
-
Accept: "application/json, text/event-stream"
|
|
1891
|
+
Accept: "application/json, text/event-stream",
|
|
1892
|
+
...this.isModernProtocol() ? options == null ? void 0 : options.headers : {},
|
|
1893
|
+
...this.isModernProtocol() && "method" in message && "id" in message ? this.getStandardRequestHeaders(message) : {}
|
|
1705
1894
|
},
|
|
1706
1895
|
includeSessionId: !isInitializeRequest
|
|
1707
1896
|
});
|
|
@@ -1733,19 +1922,31 @@ var HttpMCPTransport = class {
|
|
|
1733
1922
|
return attempt(true);
|
|
1734
1923
|
}
|
|
1735
1924
|
if (response.status === 202) {
|
|
1736
|
-
if (!this.inboundSseConnection) {
|
|
1925
|
+
if (!this.isModernProtocol() && !this.inboundSseConnection) {
|
|
1737
1926
|
this.startInboundSse();
|
|
1738
1927
|
}
|
|
1739
1928
|
return;
|
|
1740
1929
|
}
|
|
1741
1930
|
if (!response.ok) {
|
|
1742
1931
|
const text = await response.text().catch(() => null);
|
|
1932
|
+
if ("id" in message && text != null) {
|
|
1933
|
+
const jsonRpcMessage = await parseJSONRPCMessage(text).catch(
|
|
1934
|
+
() => void 0
|
|
1935
|
+
);
|
|
1936
|
+
if (jsonRpcMessage != null && "error" in jsonRpcMessage) {
|
|
1937
|
+
(_b4 = this.onmessage) == null ? void 0 : _b4.call(
|
|
1938
|
+
this,
|
|
1939
|
+
jsonRpcMessage.id == null ? { ...jsonRpcMessage, id: message.id } : jsonRpcMessage
|
|
1940
|
+
);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1743
1944
|
let errorMessage = `MCP HTTP Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}`;
|
|
1744
1945
|
if (response.status === 404) {
|
|
1745
|
-
if (sessionIdForRequest) {
|
|
1946
|
+
if (!this.isModernProtocol() && sessionIdForRequest) {
|
|
1746
1947
|
this.expireSessionId(sessionIdForRequest);
|
|
1747
1948
|
errorMessage += ". The MCP session expired. Create a new client without `initialSessionId` to start a fresh session";
|
|
1748
|
-
} else {
|
|
1949
|
+
} else if (!this.isModernProtocol()) {
|
|
1749
1950
|
errorMessage += ". This server does not support HTTP transport. Try using `sse` transport instead";
|
|
1750
1951
|
}
|
|
1751
1952
|
}
|
|
@@ -1755,7 +1956,7 @@ var HttpMCPTransport = class {
|
|
|
1755
1956
|
url: this.url.href,
|
|
1756
1957
|
responseBody: text != null ? text : void 0
|
|
1757
1958
|
});
|
|
1758
|
-
(
|
|
1959
|
+
(_c = this.onerror) == null ? void 0 : _c.call(this, error2);
|
|
1759
1960
|
throw error2;
|
|
1760
1961
|
}
|
|
1761
1962
|
const isNotification = !("id" in message);
|
|
@@ -1767,7 +1968,7 @@ var HttpMCPTransport = class {
|
|
|
1767
1968
|
const data = await response.json();
|
|
1768
1969
|
const messages = Array.isArray(data) ? data.map((message2) => validateJSONRPCMessage(message2)) : [validateJSONRPCMessage(data)];
|
|
1769
1970
|
for (const jsonRpcMessage of messages) {
|
|
1770
|
-
(
|
|
1971
|
+
(_d = this.onmessage) == null ? void 0 : _d.call(this, jsonRpcMessage);
|
|
1771
1972
|
}
|
|
1772
1973
|
return;
|
|
1773
1974
|
}
|
|
@@ -1778,7 +1979,7 @@ var HttpMCPTransport = class {
|
|
|
1778
1979
|
statusCode: response.status,
|
|
1779
1980
|
url: this.url.href
|
|
1780
1981
|
});
|
|
1781
|
-
(
|
|
1982
|
+
(_e = this.onerror) == null ? void 0 : _e.call(this, error2);
|
|
1782
1983
|
throw error2;
|
|
1783
1984
|
}
|
|
1784
1985
|
const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream2());
|
|
@@ -1824,18 +2025,29 @@ var HttpMCPTransport = class {
|
|
|
1824
2025
|
statusCode: response.status,
|
|
1825
2026
|
url: this.url.href
|
|
1826
2027
|
});
|
|
1827
|
-
(
|
|
2028
|
+
(_f = this.onerror) == null ? void 0 : _f.call(this, error);
|
|
1828
2029
|
throw error;
|
|
1829
2030
|
} catch (error) {
|
|
1830
|
-
if ((
|
|
2031
|
+
if ((_g = options == null ? void 0 : options.signal) == null ? void 0 : _g.aborted) {
|
|
1831
2032
|
throw error;
|
|
1832
2033
|
}
|
|
1833
|
-
(
|
|
2034
|
+
(_h = this.onerror) == null ? void 0 : _h.call(this, error);
|
|
1834
2035
|
throw error;
|
|
1835
2036
|
}
|
|
1836
2037
|
};
|
|
1837
2038
|
await attempt();
|
|
1838
2039
|
}
|
|
2040
|
+
getStandardRequestHeaders(message) {
|
|
2041
|
+
const headers = {
|
|
2042
|
+
"Mcp-Method": message.method
|
|
2043
|
+
};
|
|
2044
|
+
const params = message.params;
|
|
2045
|
+
const name3 = message.method === "resources/read" ? params == null ? void 0 : params.uri : message.method === "tools/call" || message.method === "prompts/get" ? params == null ? void 0 : params.name : void 0;
|
|
2046
|
+
if (typeof name3 === "string") {
|
|
2047
|
+
headers["Mcp-Name"] = encodeMCPHeaderValue(name3);
|
|
2048
|
+
}
|
|
2049
|
+
return headers;
|
|
2050
|
+
}
|
|
1839
2051
|
getNextReconnectionDelay(attempt) {
|
|
1840
2052
|
const {
|
|
1841
2053
|
initialReconnectionDelay,
|
|
@@ -1868,6 +2080,9 @@ var HttpMCPTransport = class {
|
|
|
1868
2080
|
}, delay);
|
|
1869
2081
|
}
|
|
1870
2082
|
startInboundSse(triedAuth = false, resumeToken) {
|
|
2083
|
+
if (this.isModernProtocol()) {
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
1871
2086
|
void this.openInboundSse(triedAuth, resumeToken).catch((error) => {
|
|
1872
2087
|
var _a3;
|
|
1873
2088
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -1879,6 +2094,9 @@ var HttpMCPTransport = class {
|
|
|
1879
2094
|
// Open optional inbound SSE stream; best-effort and resumable
|
|
1880
2095
|
async openInboundSse(triedAuth = false, resumeToken) {
|
|
1881
2096
|
var _a3, _b3, _c, _d, _e, _f;
|
|
2097
|
+
if (this.isModernProtocol()) {
|
|
2098
|
+
return;
|
|
2099
|
+
}
|
|
1882
2100
|
try {
|
|
1883
2101
|
const sessionIdForRequest = this.sessionId;
|
|
1884
2102
|
const headers = await this.commonHeaders({
|
|
@@ -2001,11 +2219,15 @@ var HttpMCPTransport = class {
|
|
|
2001
2219
|
|
|
2002
2220
|
// src/tool/mcp-transport.ts
|
|
2003
2221
|
function createMcpTransport(config) {
|
|
2222
|
+
var _a3;
|
|
2004
2223
|
switch (config.type) {
|
|
2005
2224
|
case "sse":
|
|
2006
2225
|
return new SseMCPTransport(config);
|
|
2007
2226
|
case "http":
|
|
2008
|
-
return new HttpMCPTransport(
|
|
2227
|
+
return new HttpMCPTransport({
|
|
2228
|
+
...config,
|
|
2229
|
+
initialProtocolVersion: (_a3 = config.initialProtocolVersion) != null ? _a3 : LATEST_PROTOCOL_VERSION
|
|
2230
|
+
});
|
|
2009
2231
|
default:
|
|
2010
2232
|
throw new MCPClientError({
|
|
2011
2233
|
message: "Unsupported or invalid transport configuration. If you are using a custom transport, make sure it implements the MCPTransport interface."
|
|
@@ -2140,6 +2362,8 @@ async function readMCPAppResource({
|
|
|
2140
2362
|
// src/tool/mcp-client.ts
|
|
2141
2363
|
var CLIENT_VERSION = "1.0.0";
|
|
2142
2364
|
var DEFAULT_MAX_TOOL_CALL_RETRIES = 0;
|
|
2365
|
+
var DEFAULT_PROTOCOL_DISCOVERY_TIMEOUT = 1e3;
|
|
2366
|
+
var MODERN_PROTOCOL_ERROR_CODES = [-32020, -32021, -32022];
|
|
2143
2367
|
var DEFAULT_RETRY_ERROR_CODES = [
|
|
2144
2368
|
"ConnectionRefused",
|
|
2145
2369
|
"ConnectionClosed",
|
|
@@ -2265,23 +2489,28 @@ var DefaultMCPClient = class {
|
|
|
2265
2489
|
maxRetries,
|
|
2266
2490
|
capabilities,
|
|
2267
2491
|
initialInitializeResult,
|
|
2268
|
-
initializationOptions
|
|
2492
|
+
initializationOptions,
|
|
2493
|
+
protocolVersionDiscovery = true
|
|
2269
2494
|
}) {
|
|
2270
2495
|
this.requestMessageId = 0;
|
|
2271
2496
|
this.responseHandlers = /* @__PURE__ */ new Map();
|
|
2272
2497
|
this.serverCapabilities = {};
|
|
2273
2498
|
this._serverInfo = { name: "", version: "" };
|
|
2274
2499
|
this._initializeResult = {
|
|
2275
|
-
protocolVersion:
|
|
2500
|
+
protocolVersion: LATEST_LEGACY_PROTOCOL_VERSION,
|
|
2276
2501
|
capabilities: {},
|
|
2277
2502
|
serverInfo: this._serverInfo
|
|
2278
2503
|
};
|
|
2504
|
+
this.protocolEra = "legacy";
|
|
2505
|
+
this.protocolVersion = LATEST_LEGACY_PROTOCOL_VERSION;
|
|
2506
|
+
this.toolHeaderBindings = /* @__PURE__ */ new Map();
|
|
2279
2507
|
this.isClosed = true;
|
|
2280
2508
|
this.onUncaughtError = onUncaughtError;
|
|
2281
2509
|
this.maxRetries = prepareMaxRetries(maxRetries);
|
|
2282
2510
|
this.clientCapabilities = capabilities != null ? capabilities : {};
|
|
2283
2511
|
this.initialInitializeResult = initialInitializeResult;
|
|
2284
2512
|
this.initializationOptions = initializationOptions;
|
|
2513
|
+
this.protocolVersionDiscovery = protocolVersionDiscovery;
|
|
2285
2514
|
if (isCustomMcpTransport(transportConfig)) {
|
|
2286
2515
|
this.transport = transportConfig;
|
|
2287
2516
|
} else {
|
|
@@ -2345,11 +2574,20 @@ var DefaultMCPClient = class {
|
|
|
2345
2574
|
this.applyInitializeResult(result2);
|
|
2346
2575
|
return this;
|
|
2347
2576
|
}
|
|
2577
|
+
if (this.protocolVersionDiscovery && this.transport.supportsProtocolVersionDiscovery) {
|
|
2578
|
+
const discovered = await this.tryProtocolDiscovery(signal);
|
|
2579
|
+
if (discovered) {
|
|
2580
|
+
return this;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
this.protocolEra = "legacy";
|
|
2584
|
+
this.protocolVersion = LATEST_LEGACY_PROTOCOL_VERSION;
|
|
2585
|
+
this.setTransportProtocolVersion(this.protocolVersion);
|
|
2348
2586
|
const result = await this.request({
|
|
2349
2587
|
request: {
|
|
2350
2588
|
method: "initialize",
|
|
2351
2589
|
params: {
|
|
2352
|
-
protocolVersion:
|
|
2590
|
+
protocolVersion: LATEST_LEGACY_PROTOCOL_VERSION,
|
|
2353
2591
|
capabilities: this.clientCapabilities,
|
|
2354
2592
|
clientInfo: this.clientInfo
|
|
2355
2593
|
}
|
|
@@ -2392,6 +2630,55 @@ var DefaultMCPClient = class {
|
|
|
2392
2630
|
}
|
|
2393
2631
|
}
|
|
2394
2632
|
}
|
|
2633
|
+
async tryProtocolDiscovery(signal) {
|
|
2634
|
+
this.protocolEra = "modern";
|
|
2635
|
+
this.protocolVersion = LATEST_PROTOCOL_VERSION;
|
|
2636
|
+
this.setTransportProtocolVersion(this.protocolVersion);
|
|
2637
|
+
try {
|
|
2638
|
+
const result = await this.request({
|
|
2639
|
+
request: { method: "server/discover" },
|
|
2640
|
+
resultSchema: DiscoverResultSchema,
|
|
2641
|
+
options: {
|
|
2642
|
+
signal,
|
|
2643
|
+
timeout: DEFAULT_PROTOCOL_DISCOVERY_TIMEOUT
|
|
2644
|
+
}
|
|
2645
|
+
});
|
|
2646
|
+
this.applyDiscoverResult(result);
|
|
2647
|
+
return true;
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
if (MCPClientError.isInstance(error) && error.code != null && MODERN_PROTOCOL_ERROR_CODES.includes(error.code)) {
|
|
2650
|
+
throw error;
|
|
2651
|
+
}
|
|
2652
|
+
return false;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
applyDiscoverResult(result) {
|
|
2656
|
+
var _a3;
|
|
2657
|
+
if (!result.supportedVersions.includes(this.protocolVersion)) {
|
|
2658
|
+
throw new MCPClientError({
|
|
2659
|
+
message: `Server does not support the requested protocol version: ${this.protocolVersion}`
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
const serverInfo = (_a3 = result._meta) == null ? void 0 : _a3["io.modelcontextprotocol/serverInfo"];
|
|
2663
|
+
if (serverInfo != null && typeof serverInfo === "object" && "name" in serverInfo && typeof serverInfo.name === "string" && "version" in serverInfo && typeof serverInfo.version === "string") {
|
|
2664
|
+
this._serverInfo = serverInfo;
|
|
2665
|
+
}
|
|
2666
|
+
this.serverCapabilities = result.capabilities;
|
|
2667
|
+
this._serverInstructions = result.instructions;
|
|
2668
|
+
this._initializeResult = {
|
|
2669
|
+
protocolVersion: this.protocolVersion,
|
|
2670
|
+
capabilities: result.capabilities,
|
|
2671
|
+
serverInfo: this._serverInfo,
|
|
2672
|
+
instructions: result.instructions
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
setTransportProtocolVersion(version) {
|
|
2676
|
+
if (this.transport.setProtocolVersion) {
|
|
2677
|
+
this.transport.setProtocolVersion(version);
|
|
2678
|
+
} else {
|
|
2679
|
+
this.transport.protocolVersion = version;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2395
2682
|
applyInitializeResult(result) {
|
|
2396
2683
|
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
2397
2684
|
throw new MCPClientError({
|
|
@@ -2399,13 +2686,11 @@ var DefaultMCPClient = class {
|
|
|
2399
2686
|
});
|
|
2400
2687
|
}
|
|
2401
2688
|
this.serverCapabilities = result.capabilities;
|
|
2689
|
+
this.protocolEra = "legacy";
|
|
2690
|
+
this.protocolVersion = result.protocolVersion;
|
|
2402
2691
|
this._serverInfo = result.serverInfo;
|
|
2403
2692
|
this._initializeResult = result;
|
|
2404
|
-
|
|
2405
|
-
this.transport.setProtocolVersion(result.protocolVersion);
|
|
2406
|
-
} else {
|
|
2407
|
-
this.transport.protocolVersion = result.protocolVersion;
|
|
2408
|
-
}
|
|
2693
|
+
this.setTransportProtocolVersion(result.protocolVersion);
|
|
2409
2694
|
this._serverInstructions = result.instructions;
|
|
2410
2695
|
}
|
|
2411
2696
|
async close() {
|
|
@@ -2414,15 +2699,13 @@ var DefaultMCPClient = class {
|
|
|
2414
2699
|
await ((_a3 = this.transport) == null ? void 0 : _a3.close());
|
|
2415
2700
|
this.onClose();
|
|
2416
2701
|
}
|
|
2417
|
-
send(message,
|
|
2418
|
-
return this.transport.send(
|
|
2419
|
-
message,
|
|
2420
|
-
signal == null ? void 0 : { signal }
|
|
2421
|
-
);
|
|
2702
|
+
send(message, options) {
|
|
2703
|
+
return options == null ? this.transport.send(message) : this.transport.send(message, options);
|
|
2422
2704
|
}
|
|
2423
2705
|
assertCapability(method) {
|
|
2424
2706
|
switch (method) {
|
|
2425
2707
|
case "initialize":
|
|
2708
|
+
case "server/discover":
|
|
2426
2709
|
break;
|
|
2427
2710
|
case "completion/complete":
|
|
2428
2711
|
if (!this.serverCapabilities.completions) {
|
|
@@ -2468,6 +2751,7 @@ var DefaultMCPClient = class {
|
|
|
2468
2751
|
options
|
|
2469
2752
|
}) {
|
|
2470
2753
|
return new Promise((resolve, reject) => {
|
|
2754
|
+
var _a3;
|
|
2471
2755
|
if (this.isClosed) {
|
|
2472
2756
|
return reject(
|
|
2473
2757
|
new MCPClientError({
|
|
@@ -2483,11 +2767,24 @@ var DefaultMCPClient = class {
|
|
|
2483
2767
|
const transportSignal = signal == null ? timeoutController == null ? void 0 : timeoutController.signal : timeoutController == null ? signal : AbortSignal.any([signal, timeoutController.signal]);
|
|
2484
2768
|
let timeoutId;
|
|
2485
2769
|
const messageId = this.requestMessageId++;
|
|
2486
|
-
const
|
|
2770
|
+
const preparedRequest = this.protocolEra === "modern" ? {
|
|
2487
2771
|
...request,
|
|
2772
|
+
params: {
|
|
2773
|
+
...request.params,
|
|
2774
|
+
_meta: {
|
|
2775
|
+
...(_a3 = request.params) == null ? void 0 : _a3._meta,
|
|
2776
|
+
"io.modelcontextprotocol/protocolVersion": this.protocolVersion,
|
|
2777
|
+
"io.modelcontextprotocol/clientCapabilities": this.clientCapabilities,
|
|
2778
|
+
"io.modelcontextprotocol/clientInfo": this.clientInfo
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
} : request;
|
|
2782
|
+
const jsonrpcRequest = {
|
|
2783
|
+
...preparedRequest,
|
|
2488
2784
|
jsonrpc: "2.0",
|
|
2489
2785
|
id: messageId
|
|
2490
2786
|
};
|
|
2787
|
+
const headers = this.getToolRequestHeaders(preparedRequest);
|
|
2491
2788
|
const rejectWithAbortError = () => {
|
|
2492
2789
|
reject(
|
|
2493
2790
|
new MCPClientError({
|
|
@@ -2527,11 +2824,21 @@ var DefaultMCPClient = class {
|
|
|
2527
2824
|
return rejectAndCleanup(response);
|
|
2528
2825
|
}
|
|
2529
2826
|
try {
|
|
2827
|
+
if (this.protocolEra === "modern" && response.result.resultType == null) {
|
|
2828
|
+
throw new MCPClientError({
|
|
2829
|
+
message: "Modern MCP result is missing resultType"
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2832
|
+
if (response.result.resultType === "input_required") {
|
|
2833
|
+
throw new MCPClientError({
|
|
2834
|
+
message: "Server requested additional input, but multi round-trip requests are not supported yet"
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2530
2837
|
const result = resultSchema.parse(response.result);
|
|
2531
2838
|
cleanup();
|
|
2532
2839
|
resolve(result);
|
|
2533
2840
|
} catch (error) {
|
|
2534
|
-
const parseError = new MCPClientError({
|
|
2841
|
+
const parseError = MCPClientError.isInstance(error) ? error : new MCPClientError({
|
|
2535
2842
|
message: "Failed to parse server response",
|
|
2536
2843
|
cause: error
|
|
2537
2844
|
});
|
|
@@ -2542,7 +2849,11 @@ var DefaultMCPClient = class {
|
|
|
2542
2849
|
if (timeout != null) {
|
|
2543
2850
|
timeoutId = setTimeout(onTimeout, timeout);
|
|
2544
2851
|
}
|
|
2545
|
-
const
|
|
2852
|
+
const sendOptions = {
|
|
2853
|
+
...transportSignal == null ? {} : { signal: transportSignal },
|
|
2854
|
+
...headers == null ? {} : { headers }
|
|
2855
|
+
};
|
|
2856
|
+
const sendPromise = Object.keys(sendOptions).length === 0 ? this.send(jsonrpcRequest) : this.send(jsonrpcRequest, sendOptions);
|
|
2546
2857
|
sendPromise.catch((error) => {
|
|
2547
2858
|
rejectAndCleanup(error);
|
|
2548
2859
|
});
|
|
@@ -2552,11 +2863,59 @@ var DefaultMCPClient = class {
|
|
|
2552
2863
|
params,
|
|
2553
2864
|
options
|
|
2554
2865
|
} = {}) {
|
|
2555
|
-
|
|
2866
|
+
const result = await this.request({
|
|
2556
2867
|
request: { method: "tools/list", params },
|
|
2557
2868
|
resultSchema: ListToolsResultSchema,
|
|
2558
2869
|
options
|
|
2559
2870
|
});
|
|
2871
|
+
return this.prepareToolDefinitions(result, (params == null ? void 0 : params.cursor) == null);
|
|
2872
|
+
}
|
|
2873
|
+
prepareToolDefinitions(definitions, resetHeaderBindings = false) {
|
|
2874
|
+
if (this.protocolEra !== "modern" || !this.transport.supportsMcpToolParameterHeaders) {
|
|
2875
|
+
return definitions;
|
|
2876
|
+
}
|
|
2877
|
+
if (resetHeaderBindings) {
|
|
2878
|
+
this.toolHeaderBindings.clear();
|
|
2879
|
+
}
|
|
2880
|
+
const tools = definitions.tools.filter((toolDefinition) => {
|
|
2881
|
+
const result = getMCPToolHeaderBindings(toolDefinition.inputSchema);
|
|
2882
|
+
if (!result.success) {
|
|
2883
|
+
this.onError(
|
|
2884
|
+
new MCPClientError({
|
|
2885
|
+
message: `Ignoring MCP tool "${toolDefinition.name}": ${result.error}`
|
|
2886
|
+
})
|
|
2887
|
+
);
|
|
2888
|
+
return false;
|
|
2889
|
+
}
|
|
2890
|
+
this.toolHeaderBindings.set(toolDefinition.name, result.bindings);
|
|
2891
|
+
return true;
|
|
2892
|
+
});
|
|
2893
|
+
return { ...definitions, tools };
|
|
2894
|
+
}
|
|
2895
|
+
getToolRequestHeaders(request) {
|
|
2896
|
+
var _a3;
|
|
2897
|
+
if (this.protocolEra !== "modern" || request.method !== "tools/call" || typeof ((_a3 = request.params) == null ? void 0 : _a3.name) !== "string") {
|
|
2898
|
+
return void 0;
|
|
2899
|
+
}
|
|
2900
|
+
const bindings = this.toolHeaderBindings.get(request.params.name);
|
|
2901
|
+
if (bindings == null || bindings.length === 0) {
|
|
2902
|
+
return void 0;
|
|
2903
|
+
}
|
|
2904
|
+
const args = request.params.arguments;
|
|
2905
|
+
if (args == null || typeof args !== "object" || Array.isArray(args)) {
|
|
2906
|
+
return void 0;
|
|
2907
|
+
}
|
|
2908
|
+
try {
|
|
2909
|
+
return createMCPToolHeaders({
|
|
2910
|
+
bindings,
|
|
2911
|
+
args
|
|
2912
|
+
});
|
|
2913
|
+
} catch (error) {
|
|
2914
|
+
throw new MCPClientError({
|
|
2915
|
+
message: `Failed to create MCP headers for tool "${request.params.name}"`,
|
|
2916
|
+
cause: error
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2560
2919
|
}
|
|
2561
2920
|
async callToolWithRetry({
|
|
2562
2921
|
options,
|
|
@@ -2682,7 +3041,10 @@ var DefaultMCPClient = class {
|
|
|
2682
3041
|
jsonrpc: "2.0"
|
|
2683
3042
|
};
|
|
2684
3043
|
await waitForAbort(
|
|
2685
|
-
this.send(
|
|
3044
|
+
this.send(
|
|
3045
|
+
jsonrpcNotification,
|
|
3046
|
+
(options == null ? void 0 : options.signal) == null ? void 0 : { signal: options.signal }
|
|
3047
|
+
),
|
|
2686
3048
|
options == null ? void 0 : options.signal
|
|
2687
3049
|
);
|
|
2688
3050
|
}
|
|
@@ -2704,6 +3066,7 @@ var DefaultMCPClient = class {
|
|
|
2704
3066
|
*/
|
|
2705
3067
|
toolsFromDefinitions(definitions, { schemas = "automatic" } = {}) {
|
|
2706
3068
|
var _a3, _b3;
|
|
3069
|
+
definitions = this.prepareToolDefinitions(definitions);
|
|
2707
3070
|
const tools = {};
|
|
2708
3071
|
for (const {
|
|
2709
3072
|
name: name3,
|
|
@@ -2937,6 +3300,16 @@ var DefaultMCPClient = class {
|
|
|
2937
3300
|
}
|
|
2938
3301
|
}
|
|
2939
3302
|
onResponse(response) {
|
|
3303
|
+
if (response.id == null) {
|
|
3304
|
+
this.onError(
|
|
3305
|
+
new MCPClientError({
|
|
3306
|
+
message: `Protocol error: Received a response without a message ID: ${JSON.stringify(
|
|
3307
|
+
response
|
|
3308
|
+
)}`
|
|
3309
|
+
})
|
|
3310
|
+
);
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
2940
3313
|
const messageId = Number(response.id);
|
|
2941
3314
|
const handler = this.responseHandlers.get(messageId);
|
|
2942
3315
|
if (handler === void 0) {
|
|
@@ -2959,7 +3332,7 @@ var DefaultMCPClient = class {
|
|
|
2959
3332
|
};
|
|
2960
3333
|
|
|
2961
3334
|
// src/tool/mcp-app-fingerprint.ts
|
|
2962
|
-
import { convertUint8ArrayToBase64 } from "@ai-sdk/provider-utils";
|
|
3335
|
+
import { convertUint8ArrayToBase64 as convertUint8ArrayToBase642 } from "@ai-sdk/provider-utils";
|
|
2963
3336
|
var encoder = new TextEncoder();
|
|
2964
3337
|
function canonicalJSON(value) {
|
|
2965
3338
|
if (value == null || typeof value !== "object") {
|
|
@@ -2973,7 +3346,7 @@ function canonicalJSON(value) {
|
|
|
2973
3346
|
return `{${entries.join(",")}}`;
|
|
2974
3347
|
}
|
|
2975
3348
|
function toBase64url(bytes) {
|
|
2976
|
-
return
|
|
3349
|
+
return convertUint8ArrayToBase642(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
2977
3350
|
}
|
|
2978
3351
|
async function fingerprintMCPAppResource(resource) {
|
|
2979
3352
|
var _a3, _b3, _c, _d;
|