@ai-sdk/mcp 0.0.1

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/dist/index.js ADDED
@@ -0,0 +1,1754 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name3 in all)
10
+ __defProp(target, name3, { get: all[name3], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ UnauthorizedError: () => UnauthorizedError,
34
+ auth: () => auth,
35
+ experimental_createMCPClient: () => createMCPClient
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+
39
+ // src/tool/mcp-client.ts
40
+ var import_provider_utils3 = require("@ai-sdk/provider-utils");
41
+
42
+ // src/error/mcp-client-error.ts
43
+ var import_provider = require("@ai-sdk/provider");
44
+ var name = "AI_MCPClientError";
45
+ var marker = `vercel.ai.error.${name}`;
46
+ var symbol = Symbol.for(marker);
47
+ var _a, _b;
48
+ var MCPClientError = class extends (_b = import_provider.AISDKError, _a = symbol, _b) {
49
+ constructor({
50
+ name: name3 = "MCPClientError",
51
+ message,
52
+ cause,
53
+ data,
54
+ code
55
+ }) {
56
+ super({ name: name3, message, cause });
57
+ this[_a] = true;
58
+ this.data = data;
59
+ this.code = code;
60
+ }
61
+ static isInstance(error) {
62
+ return import_provider.AISDKError.hasMarker(error, marker);
63
+ }
64
+ };
65
+
66
+ // src/tool/mcp-sse-transport.ts
67
+ var import_provider_utils = require("@ai-sdk/provider-utils");
68
+
69
+ // src/tool/json-rpc-message.ts
70
+ var import_v42 = require("zod/v4");
71
+
72
+ // src/tool/types.ts
73
+ var import_v4 = require("zod/v4");
74
+ var LATEST_PROTOCOL_VERSION = "2025-06-18";
75
+ var SUPPORTED_PROTOCOL_VERSIONS = [
76
+ LATEST_PROTOCOL_VERSION,
77
+ "2025-03-26",
78
+ "2024-11-05"
79
+ ];
80
+ var ClientOrServerImplementationSchema = import_v4.z.looseObject({
81
+ name: import_v4.z.string(),
82
+ version: import_v4.z.string()
83
+ });
84
+ var BaseParamsSchema = import_v4.z.looseObject({
85
+ _meta: import_v4.z.optional(import_v4.z.object({}).loose())
86
+ });
87
+ var ResultSchema = BaseParamsSchema;
88
+ var RequestSchema = import_v4.z.object({
89
+ method: import_v4.z.string(),
90
+ params: import_v4.z.optional(BaseParamsSchema)
91
+ });
92
+ var ServerCapabilitiesSchema = import_v4.z.looseObject({
93
+ experimental: import_v4.z.optional(import_v4.z.object({}).loose()),
94
+ logging: import_v4.z.optional(import_v4.z.object({}).loose()),
95
+ prompts: import_v4.z.optional(
96
+ import_v4.z.looseObject({
97
+ listChanged: import_v4.z.optional(import_v4.z.boolean())
98
+ })
99
+ ),
100
+ resources: import_v4.z.optional(
101
+ import_v4.z.looseObject({
102
+ subscribe: import_v4.z.optional(import_v4.z.boolean()),
103
+ listChanged: import_v4.z.optional(import_v4.z.boolean())
104
+ })
105
+ ),
106
+ tools: import_v4.z.optional(
107
+ import_v4.z.looseObject({
108
+ listChanged: import_v4.z.optional(import_v4.z.boolean())
109
+ })
110
+ )
111
+ });
112
+ var InitializeResultSchema = ResultSchema.extend({
113
+ protocolVersion: import_v4.z.string(),
114
+ capabilities: ServerCapabilitiesSchema,
115
+ serverInfo: ClientOrServerImplementationSchema,
116
+ instructions: import_v4.z.optional(import_v4.z.string())
117
+ });
118
+ var PaginatedResultSchema = ResultSchema.extend({
119
+ nextCursor: import_v4.z.optional(import_v4.z.string())
120
+ });
121
+ var ToolSchema = import_v4.z.object({
122
+ name: import_v4.z.string(),
123
+ description: import_v4.z.optional(import_v4.z.string()),
124
+ inputSchema: import_v4.z.object({
125
+ type: import_v4.z.literal("object"),
126
+ properties: import_v4.z.optional(import_v4.z.object({}).loose())
127
+ }).loose()
128
+ }).loose();
129
+ var ListToolsResultSchema = PaginatedResultSchema.extend({
130
+ tools: import_v4.z.array(ToolSchema)
131
+ });
132
+ var TextContentSchema = import_v4.z.object({
133
+ type: import_v4.z.literal("text"),
134
+ text: import_v4.z.string()
135
+ }).loose();
136
+ var ImageContentSchema = import_v4.z.object({
137
+ type: import_v4.z.literal("image"),
138
+ data: import_v4.z.base64(),
139
+ mimeType: import_v4.z.string()
140
+ }).loose();
141
+ var ResourceContentsSchema = import_v4.z.object({
142
+ /**
143
+ * The URI of this resource.
144
+ */
145
+ uri: import_v4.z.string(),
146
+ /**
147
+ * The MIME type of this resource, if known.
148
+ */
149
+ mimeType: import_v4.z.optional(import_v4.z.string())
150
+ }).loose();
151
+ var TextResourceContentsSchema = ResourceContentsSchema.extend({
152
+ text: import_v4.z.string()
153
+ });
154
+ var BlobResourceContentsSchema = ResourceContentsSchema.extend({
155
+ blob: import_v4.z.base64()
156
+ });
157
+ var EmbeddedResourceSchema = import_v4.z.object({
158
+ type: import_v4.z.literal("resource"),
159
+ resource: import_v4.z.union([TextResourceContentsSchema, BlobResourceContentsSchema])
160
+ }).loose();
161
+ var CallToolResultSchema = ResultSchema.extend({
162
+ content: import_v4.z.array(
163
+ import_v4.z.union([TextContentSchema, ImageContentSchema, EmbeddedResourceSchema])
164
+ ),
165
+ isError: import_v4.z.boolean().default(false).optional()
166
+ }).or(
167
+ ResultSchema.extend({
168
+ toolResult: import_v4.z.unknown()
169
+ })
170
+ );
171
+
172
+ // src/tool/json-rpc-message.ts
173
+ var JSONRPC_VERSION = "2.0";
174
+ var JSONRPCRequestSchema = import_v42.z.object({
175
+ jsonrpc: import_v42.z.literal(JSONRPC_VERSION),
176
+ id: import_v42.z.union([import_v42.z.string(), import_v42.z.number().int()])
177
+ }).merge(RequestSchema).strict();
178
+ var JSONRPCResponseSchema = import_v42.z.object({
179
+ jsonrpc: import_v42.z.literal(JSONRPC_VERSION),
180
+ id: import_v42.z.union([import_v42.z.string(), import_v42.z.number().int()]),
181
+ result: ResultSchema
182
+ }).strict();
183
+ var JSONRPCErrorSchema = import_v42.z.object({
184
+ jsonrpc: import_v42.z.literal(JSONRPC_VERSION),
185
+ id: import_v42.z.union([import_v42.z.string(), import_v42.z.number().int()]),
186
+ error: import_v42.z.object({
187
+ code: import_v42.z.number().int(),
188
+ message: import_v42.z.string(),
189
+ data: import_v42.z.optional(import_v42.z.unknown())
190
+ })
191
+ }).strict();
192
+ var JSONRPCNotificationSchema = import_v42.z.object({
193
+ jsonrpc: import_v42.z.literal(JSONRPC_VERSION)
194
+ }).merge(
195
+ import_v42.z.object({
196
+ method: import_v42.z.string(),
197
+ params: import_v42.z.optional(BaseParamsSchema)
198
+ })
199
+ ).strict();
200
+ var JSONRPCMessageSchema = import_v42.z.union([
201
+ JSONRPCRequestSchema,
202
+ JSONRPCNotificationSchema,
203
+ JSONRPCResponseSchema,
204
+ JSONRPCErrorSchema
205
+ ]);
206
+
207
+ // src/version.ts
208
+ var VERSION = typeof __PACKAGE_VERSION__ !== "undefined" ? __PACKAGE_VERSION__ : "0.0.0-test";
209
+
210
+ // src/tool/oauth.ts
211
+ var import_pkce_challenge = __toESM(require("pkce-challenge"));
212
+
213
+ // src/tool/oauth-types.ts
214
+ var import_v43 = require("zod/v4");
215
+ var OAuthTokensSchema = import_v43.z.object({
216
+ access_token: import_v43.z.string(),
217
+ id_token: import_v43.z.string().optional(),
218
+ // Optional for OAuth 2.1, but necessary in OpenID Connect
219
+ token_type: import_v43.z.string(),
220
+ expires_in: import_v43.z.number().optional(),
221
+ scope: import_v43.z.string().optional(),
222
+ refresh_token: import_v43.z.string().optional()
223
+ }).strip();
224
+ var SafeUrlSchema = import_v43.z.string().url().superRefine((val, ctx) => {
225
+ if (!URL.canParse(val)) {
226
+ ctx.addIssue({
227
+ code: import_v43.z.ZodIssueCode.custom,
228
+ message: "URL must be parseable",
229
+ fatal: true
230
+ });
231
+ return import_v43.z.NEVER;
232
+ }
233
+ }).refine(
234
+ (url) => {
235
+ const u = new URL(url);
236
+ return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
237
+ },
238
+ { message: "URL cannot use javascript:, data:, or vbscript: scheme" }
239
+ );
240
+ var OAuthProtectedResourceMetadataSchema = import_v43.z.object({
241
+ resource: import_v43.z.string().url(),
242
+ authorization_servers: import_v43.z.array(SafeUrlSchema).optional(),
243
+ jwks_uri: import_v43.z.string().url().optional(),
244
+ scopes_supported: import_v43.z.array(import_v43.z.string()).optional(),
245
+ bearer_methods_supported: import_v43.z.array(import_v43.z.string()).optional(),
246
+ resource_signing_alg_values_supported: import_v43.z.array(import_v43.z.string()).optional(),
247
+ resource_name: import_v43.z.string().optional(),
248
+ resource_documentation: import_v43.z.string().optional(),
249
+ resource_policy_uri: import_v43.z.string().url().optional(),
250
+ resource_tos_uri: import_v43.z.string().url().optional(),
251
+ tls_client_certificate_bound_access_tokens: import_v43.z.boolean().optional(),
252
+ authorization_details_types_supported: import_v43.z.array(import_v43.z.string()).optional(),
253
+ dpop_signing_alg_values_supported: import_v43.z.array(import_v43.z.string()).optional(),
254
+ dpop_bound_access_tokens_required: import_v43.z.boolean().optional()
255
+ }).passthrough();
256
+ var OAuthMetadataSchema = import_v43.z.object({
257
+ issuer: import_v43.z.string(),
258
+ authorization_endpoint: SafeUrlSchema,
259
+ token_endpoint: SafeUrlSchema,
260
+ registration_endpoint: SafeUrlSchema.optional(),
261
+ scopes_supported: import_v43.z.array(import_v43.z.string()).optional(),
262
+ response_types_supported: import_v43.z.array(import_v43.z.string()),
263
+ grant_types_supported: import_v43.z.array(import_v43.z.string()).optional(),
264
+ code_challenge_methods_supported: import_v43.z.array(import_v43.z.string()),
265
+ token_endpoint_auth_methods_supported: import_v43.z.array(import_v43.z.string()).optional(),
266
+ token_endpoint_auth_signing_alg_values_supported: import_v43.z.array(import_v43.z.string()).optional()
267
+ }).passthrough();
268
+ var OpenIdProviderMetadataSchema = import_v43.z.object({
269
+ issuer: import_v43.z.string(),
270
+ authorization_endpoint: SafeUrlSchema,
271
+ token_endpoint: SafeUrlSchema,
272
+ userinfo_endpoint: SafeUrlSchema.optional(),
273
+ jwks_uri: SafeUrlSchema,
274
+ registration_endpoint: SafeUrlSchema.optional(),
275
+ scopes_supported: import_v43.z.array(import_v43.z.string()).optional(),
276
+ response_types_supported: import_v43.z.array(import_v43.z.string()),
277
+ grant_types_supported: import_v43.z.array(import_v43.z.string()).optional(),
278
+ subject_types_supported: import_v43.z.array(import_v43.z.string()),
279
+ id_token_signing_alg_values_supported: import_v43.z.array(import_v43.z.string()),
280
+ claims_supported: import_v43.z.array(import_v43.z.string()).optional(),
281
+ token_endpoint_auth_methods_supported: import_v43.z.array(import_v43.z.string()).optional()
282
+ }).passthrough();
283
+ var OpenIdProviderDiscoveryMetadataSchema = OpenIdProviderMetadataSchema.merge(
284
+ OAuthMetadataSchema.pick({
285
+ code_challenge_methods_supported: true
286
+ })
287
+ );
288
+ var OAuthClientInformationSchema = import_v43.z.object({
289
+ client_id: import_v43.z.string(),
290
+ client_secret: import_v43.z.string().optional(),
291
+ client_id_issued_at: import_v43.z.number().optional(),
292
+ client_secret_expires_at: import_v43.z.number().optional()
293
+ }).strip();
294
+ var OAuthClientMetadataSchema = import_v43.z.object({
295
+ redirect_uris: import_v43.z.array(SafeUrlSchema),
296
+ token_endpoint_auth_method: import_v43.z.string().optional(),
297
+ grant_types: import_v43.z.array(import_v43.z.string()).optional(),
298
+ response_types: import_v43.z.array(import_v43.z.string()).optional(),
299
+ client_name: import_v43.z.string().optional(),
300
+ client_uri: SafeUrlSchema.optional(),
301
+ logo_uri: SafeUrlSchema.optional(),
302
+ scope: import_v43.z.string().optional(),
303
+ contacts: import_v43.z.array(import_v43.z.string()).optional(),
304
+ tos_uri: SafeUrlSchema.optional(),
305
+ policy_uri: import_v43.z.string().optional(),
306
+ jwks_uri: SafeUrlSchema.optional(),
307
+ jwks: import_v43.z.any().optional(),
308
+ software_id: import_v43.z.string().optional(),
309
+ software_version: import_v43.z.string().optional(),
310
+ software_statement: import_v43.z.string().optional()
311
+ }).strip();
312
+ var OAuthErrorResponseSchema = import_v43.z.object({
313
+ error: import_v43.z.string(),
314
+ error_description: import_v43.z.string().optional(),
315
+ error_uri: import_v43.z.string().optional()
316
+ });
317
+ var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(
318
+ OAuthClientInformationSchema
319
+ );
320
+
321
+ // src/error/oauth-error.ts
322
+ var import_provider2 = require("@ai-sdk/provider");
323
+ var name2 = "AI_MCPClientOAuthError";
324
+ var marker2 = `vercel.ai.error.${name2}`;
325
+ var symbol2 = Symbol.for(marker2);
326
+ var _a2, _b2;
327
+ var MCPClientOAuthError = class extends (_b2 = import_provider2.AISDKError, _a2 = symbol2, _b2) {
328
+ constructor({
329
+ name: name3 = "MCPClientOAuthError",
330
+ message,
331
+ cause
332
+ }) {
333
+ super({ name: name3, message, cause });
334
+ this[_a2] = true;
335
+ }
336
+ static isInstance(error) {
337
+ return import_provider2.AISDKError.hasMarker(error, marker2);
338
+ }
339
+ };
340
+ var ServerError = class extends MCPClientOAuthError {
341
+ };
342
+ ServerError.errorCode = "server_error";
343
+ var InvalidClientError = class extends MCPClientOAuthError {
344
+ };
345
+ InvalidClientError.errorCode = "invalid_client";
346
+ var InvalidGrantError = class extends MCPClientOAuthError {
347
+ };
348
+ InvalidGrantError.errorCode = "invalid_grant";
349
+ var UnauthorizedClientError = class extends MCPClientOAuthError {
350
+ };
351
+ UnauthorizedClientError.errorCode = "unauthorized_client";
352
+ var OAUTH_ERRORS = {
353
+ [ServerError.errorCode]: ServerError,
354
+ [InvalidClientError.errorCode]: InvalidClientError,
355
+ [InvalidGrantError.errorCode]: InvalidGrantError,
356
+ [UnauthorizedClientError.errorCode]: UnauthorizedClientError
357
+ };
358
+
359
+ // src/util/oauth-util.ts
360
+ function resourceUrlFromServerUrl(url) {
361
+ const resourceURL = typeof url === "string" ? new URL(url) : new URL(url.href);
362
+ resourceURL.hash = "";
363
+ return resourceURL;
364
+ }
365
+ function checkResourceAllowed({
366
+ requestedResource,
367
+ configuredResource
368
+ }) {
369
+ const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
370
+ const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
371
+ if (requested.origin !== configured.origin) {
372
+ return false;
373
+ }
374
+ if (requested.pathname.length < configured.pathname.length) {
375
+ return false;
376
+ }
377
+ const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
378
+ const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
379
+ return requestedPath.startsWith(configuredPath);
380
+ }
381
+
382
+ // src/tool/oauth.ts
383
+ var UnauthorizedError = class extends Error {
384
+ constructor(message = "Unauthorized") {
385
+ super(message);
386
+ this.name = "UnauthorizedError";
387
+ }
388
+ };
389
+ function extractResourceMetadataUrl(response) {
390
+ var _a3;
391
+ const header = (_a3 = response.headers.get("www-authenticate")) != null ? _a3 : response.headers.get("WWW-Authenticate");
392
+ if (!header) {
393
+ return void 0;
394
+ }
395
+ const [type, scheme] = header.split(" ");
396
+ if (type.toLowerCase() !== "bearer" || !scheme) {
397
+ return void 0;
398
+ }
399
+ const regex = /resource_metadata="([^"]*)"/;
400
+ const match = header.match(regex);
401
+ if (!match) {
402
+ return void 0;
403
+ }
404
+ try {
405
+ return new URL(match[1]);
406
+ } catch (e) {
407
+ return void 0;
408
+ }
409
+ }
410
+ function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
411
+ if (pathname.endsWith("/")) {
412
+ pathname = pathname.slice(0, -1);
413
+ }
414
+ return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
415
+ }
416
+ async function fetchWithCorsRetry(url, headers, fetchFn = fetch) {
417
+ try {
418
+ return await fetchFn(url, { headers });
419
+ } catch (error) {
420
+ if (error instanceof TypeError) {
421
+ if (headers) {
422
+ return fetchWithCorsRetry(url, void 0, fetchFn);
423
+ } else {
424
+ return void 0;
425
+ }
426
+ }
427
+ throw error;
428
+ }
429
+ }
430
+ async function tryMetadataDiscovery(url, protocolVersion, fetchFn = fetch) {
431
+ const headers = {
432
+ "MCP-Protocol-Version": protocolVersion
433
+ };
434
+ return await fetchWithCorsRetry(url, headers, fetchFn);
435
+ }
436
+ function shouldAttemptFallback(response, pathname) {
437
+ return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
438
+ }
439
+ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
440
+ var _a3, _b3;
441
+ const issuer = new URL(serverUrl);
442
+ const protocolVersion = (_a3 = opts == null ? void 0 : opts.protocolVersion) != null ? _a3 : LATEST_PROTOCOL_VERSION;
443
+ let url;
444
+ if (opts == null ? void 0 : opts.metadataUrl) {
445
+ url = new URL(opts.metadataUrl);
446
+ } else {
447
+ const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
448
+ url = new URL(wellKnownPath, (_b3 = opts == null ? void 0 : opts.metadataServerUrl) != null ? _b3 : issuer);
449
+ url.search = issuer.search;
450
+ }
451
+ let response = await tryMetadataDiscovery(url, protocolVersion, fetchFn);
452
+ if (!(opts == null ? void 0 : opts.metadataUrl) && shouldAttemptFallback(response, issuer.pathname)) {
453
+ const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
454
+ response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
455
+ }
456
+ return response;
457
+ }
458
+ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
459
+ const response = await discoverMetadataWithFallback(
460
+ serverUrl,
461
+ "oauth-protected-resource",
462
+ fetchFn,
463
+ {
464
+ protocolVersion: opts == null ? void 0 : opts.protocolVersion,
465
+ metadataUrl: opts == null ? void 0 : opts.resourceMetadataUrl
466
+ }
467
+ );
468
+ if (!response || response.status === 404) {
469
+ throw new Error(
470
+ `Resource server does not implement OAuth 2.0 Protected Resource Metadata.`
471
+ );
472
+ }
473
+ if (!response.ok) {
474
+ throw new Error(
475
+ `HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`
476
+ );
477
+ }
478
+ return OAuthProtectedResourceMetadataSchema.parse(await response.json());
479
+ }
480
+ function buildDiscoveryUrls(authorizationServerUrl) {
481
+ const url = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
482
+ const hasPath = url.pathname !== "/";
483
+ const urlsToTry = [];
484
+ if (!hasPath) {
485
+ urlsToTry.push({
486
+ url: new URL("/.well-known/oauth-authorization-server", url.origin),
487
+ type: "oauth"
488
+ });
489
+ urlsToTry.push({
490
+ url: new URL("/.well-known/openid-configuration", url.origin),
491
+ type: "oidc"
492
+ });
493
+ return urlsToTry;
494
+ }
495
+ let pathname = url.pathname;
496
+ if (pathname.endsWith("/")) {
497
+ pathname = pathname.slice(0, -1);
498
+ }
499
+ urlsToTry.push({
500
+ url: new URL(
501
+ `/.well-known/oauth-authorization-server${pathname}`,
502
+ url.origin
503
+ ),
504
+ type: "oauth"
505
+ });
506
+ urlsToTry.push({
507
+ url: new URL("/.well-known/oauth-authorization-server", url.origin),
508
+ type: "oauth"
509
+ });
510
+ urlsToTry.push({
511
+ url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
512
+ type: "oidc"
513
+ });
514
+ urlsToTry.push({
515
+ url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
516
+ type: "oidc"
517
+ });
518
+ return urlsToTry;
519
+ }
520
+ async function discoverAuthorizationServerMetadata(authorizationServerUrl, {
521
+ fetchFn = fetch,
522
+ protocolVersion = LATEST_PROTOCOL_VERSION
523
+ } = {}) {
524
+ var _a3;
525
+ const headers = { "MCP-Protocol-Version": protocolVersion };
526
+ const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
527
+ for (const { url: endpointUrl, type } of urlsToTry) {
528
+ const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
529
+ if (!response) {
530
+ continue;
531
+ }
532
+ if (!response.ok) {
533
+ if (response.status >= 400 && response.status < 500) {
534
+ continue;
535
+ }
536
+ throw new Error(
537
+ `HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`
538
+ );
539
+ }
540
+ if (type === "oauth") {
541
+ return OAuthMetadataSchema.parse(await response.json());
542
+ } else {
543
+ const metadata = OpenIdProviderDiscoveryMetadataSchema.parse(
544
+ await response.json()
545
+ );
546
+ if (!((_a3 = metadata.code_challenge_methods_supported) == null ? void 0 : _a3.includes("S256"))) {
547
+ throw new Error(
548
+ `Incompatible OIDC provider at ${endpointUrl}: does not support S256 code challenge method required by MCP specification`
549
+ );
550
+ }
551
+ return metadata;
552
+ }
553
+ }
554
+ return void 0;
555
+ }
556
+ async function startAuthorization(authorizationServerUrl, {
557
+ metadata,
558
+ clientInformation,
559
+ redirectUrl,
560
+ scope,
561
+ state,
562
+ resource
563
+ }) {
564
+ const responseType = "code";
565
+ const codeChallengeMethod = "S256";
566
+ let authorizationUrl;
567
+ if (metadata) {
568
+ authorizationUrl = new URL(metadata.authorization_endpoint);
569
+ if (!metadata.response_types_supported.includes(responseType)) {
570
+ throw new Error(
571
+ `Incompatible auth server: does not support response type ${responseType}`
572
+ );
573
+ }
574
+ if (!metadata.code_challenge_methods_supported || !metadata.code_challenge_methods_supported.includes(codeChallengeMethod)) {
575
+ throw new Error(
576
+ `Incompatible auth server: does not support code challenge method ${codeChallengeMethod}`
577
+ );
578
+ }
579
+ } else {
580
+ authorizationUrl = new URL("/authorize", authorizationServerUrl);
581
+ }
582
+ const challenge = await (0, import_pkce_challenge.default)();
583
+ const codeVerifier = challenge.code_verifier;
584
+ const codeChallenge = challenge.code_challenge;
585
+ authorizationUrl.searchParams.set("response_type", responseType);
586
+ authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
587
+ authorizationUrl.searchParams.set("code_challenge", codeChallenge);
588
+ authorizationUrl.searchParams.set(
589
+ "code_challenge_method",
590
+ codeChallengeMethod
591
+ );
592
+ authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
593
+ if (state) {
594
+ authorizationUrl.searchParams.set("state", state);
595
+ }
596
+ if (scope) {
597
+ authorizationUrl.searchParams.set("scope", scope);
598
+ }
599
+ if (scope == null ? void 0 : scope.includes("offline_access")) {
600
+ authorizationUrl.searchParams.append("prompt", "consent");
601
+ }
602
+ if (resource) {
603
+ authorizationUrl.searchParams.set("resource", resource.href);
604
+ }
605
+ return { authorizationUrl, codeVerifier };
606
+ }
607
+ function selectClientAuthMethod(clientInformation, supportedMethods) {
608
+ const hasClientSecret = clientInformation.client_secret !== void 0;
609
+ if (supportedMethods.length === 0) {
610
+ return hasClientSecret ? "client_secret_post" : "none";
611
+ }
612
+ if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
613
+ return "client_secret_basic";
614
+ }
615
+ if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
616
+ return "client_secret_post";
617
+ }
618
+ if (supportedMethods.includes("none")) {
619
+ return "none";
620
+ }
621
+ return hasClientSecret ? "client_secret_post" : "none";
622
+ }
623
+ function applyClientAuthentication(method, clientInformation, headers, params) {
624
+ const { client_id, client_secret } = clientInformation;
625
+ switch (method) {
626
+ case "client_secret_basic":
627
+ applyBasicAuth(client_id, client_secret, headers);
628
+ return;
629
+ case "client_secret_post":
630
+ applyPostAuth(client_id, client_secret, params);
631
+ return;
632
+ case "none":
633
+ applyPublicAuth(client_id, params);
634
+ return;
635
+ default:
636
+ throw new Error(`Unsupported client authentication method: ${method}`);
637
+ }
638
+ }
639
+ function applyBasicAuth(clientId, clientSecret, headers) {
640
+ if (!clientSecret) {
641
+ throw new Error(
642
+ "client_secret_basic authentication requires a client_secret"
643
+ );
644
+ }
645
+ const credentials = btoa(`${clientId}:${clientSecret}`);
646
+ headers.set("Authorization", `Basic ${credentials}`);
647
+ }
648
+ function applyPostAuth(clientId, clientSecret, params) {
649
+ params.set("client_id", clientId);
650
+ if (clientSecret) {
651
+ params.set("client_secret", clientSecret);
652
+ }
653
+ }
654
+ function applyPublicAuth(clientId, params) {
655
+ params.set("client_id", clientId);
656
+ }
657
+ async function parseErrorResponse(input) {
658
+ const statusCode = input instanceof Response ? input.status : void 0;
659
+ const body = input instanceof Response ? await input.text() : input;
660
+ try {
661
+ const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
662
+ const { error, error_description, error_uri } = result;
663
+ const errorClass = OAUTH_ERRORS[error] || ServerError;
664
+ return new errorClass({
665
+ message: error_description || "",
666
+ cause: error_uri
667
+ });
668
+ } catch (error) {
669
+ const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error}. Raw body: ${body}`;
670
+ return new ServerError({ message: errorMessage });
671
+ }
672
+ }
673
+ async function exchangeAuthorization(authorizationServerUrl, {
674
+ metadata,
675
+ clientInformation,
676
+ authorizationCode,
677
+ codeVerifier,
678
+ redirectUri,
679
+ resource,
680
+ addClientAuthentication,
681
+ fetchFn
682
+ }) {
683
+ var _a3;
684
+ const grantType = "authorization_code";
685
+ const tokenUrl = (metadata == null ? void 0 : metadata.token_endpoint) ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
686
+ if ((metadata == null ? void 0 : metadata.grant_types_supported) && !metadata.grant_types_supported.includes(grantType)) {
687
+ throw new Error(
688
+ `Incompatible auth server: does not support grant type ${grantType}`
689
+ );
690
+ }
691
+ const headers = new Headers({
692
+ "Content-Type": "application/x-www-form-urlencoded",
693
+ Accept: "application/json"
694
+ });
695
+ const params = new URLSearchParams({
696
+ grant_type: grantType,
697
+ code: authorizationCode,
698
+ code_verifier: codeVerifier,
699
+ redirect_uri: String(redirectUri)
700
+ });
701
+ if (addClientAuthentication) {
702
+ addClientAuthentication(headers, params, authorizationServerUrl, metadata);
703
+ } else {
704
+ const supportedMethods = (_a3 = metadata == null ? void 0 : metadata.token_endpoint_auth_methods_supported) != null ? _a3 : [];
705
+ const authMethod = selectClientAuthMethod(
706
+ clientInformation,
707
+ supportedMethods
708
+ );
709
+ applyClientAuthentication(authMethod, clientInformation, headers, params);
710
+ }
711
+ if (resource) {
712
+ params.set("resource", resource.href);
713
+ }
714
+ const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
715
+ method: "POST",
716
+ headers,
717
+ body: params
718
+ });
719
+ if (!response.ok) {
720
+ throw await parseErrorResponse(response);
721
+ }
722
+ return OAuthTokensSchema.parse(await response.json());
723
+ }
724
+ async function refreshAuthorization(authorizationServerUrl, {
725
+ metadata,
726
+ clientInformation,
727
+ refreshToken,
728
+ resource,
729
+ addClientAuthentication,
730
+ fetchFn
731
+ }) {
732
+ var _a3;
733
+ const grantType = "refresh_token";
734
+ let tokenUrl;
735
+ if (metadata) {
736
+ tokenUrl = new URL(metadata.token_endpoint);
737
+ if (metadata.grant_types_supported && !metadata.grant_types_supported.includes(grantType)) {
738
+ throw new Error(
739
+ `Incompatible auth server: does not support grant type ${grantType}`
740
+ );
741
+ }
742
+ } else {
743
+ tokenUrl = new URL("/token", authorizationServerUrl);
744
+ }
745
+ const headers = new Headers({
746
+ "Content-Type": "application/x-www-form-urlencoded"
747
+ });
748
+ const params = new URLSearchParams({
749
+ grant_type: grantType,
750
+ refresh_token: refreshToken
751
+ });
752
+ if (addClientAuthentication) {
753
+ addClientAuthentication(headers, params, authorizationServerUrl, metadata);
754
+ } else {
755
+ const supportedMethods = (_a3 = metadata == null ? void 0 : metadata.token_endpoint_auth_methods_supported) != null ? _a3 : [];
756
+ const authMethod = selectClientAuthMethod(
757
+ clientInformation,
758
+ supportedMethods
759
+ );
760
+ applyClientAuthentication(authMethod, clientInformation, headers, params);
761
+ }
762
+ if (resource) {
763
+ params.set("resource", resource.href);
764
+ }
765
+ const response = await (fetchFn != null ? fetchFn : fetch)(tokenUrl, {
766
+ method: "POST",
767
+ headers,
768
+ body: params
769
+ });
770
+ if (!response.ok) {
771
+ throw await parseErrorResponse(response);
772
+ }
773
+ return OAuthTokensSchema.parse({
774
+ refresh_token: refreshToken,
775
+ ...await response.json()
776
+ });
777
+ }
778
+ async function registerClient(authorizationServerUrl, {
779
+ metadata,
780
+ clientMetadata,
781
+ fetchFn
782
+ }) {
783
+ let registrationUrl;
784
+ if (metadata) {
785
+ if (!metadata.registration_endpoint) {
786
+ throw new Error(
787
+ "Incompatible auth server: does not support dynamic client registration"
788
+ );
789
+ }
790
+ registrationUrl = new URL(metadata.registration_endpoint);
791
+ } else {
792
+ registrationUrl = new URL("/register", authorizationServerUrl);
793
+ }
794
+ const response = await (fetchFn != null ? fetchFn : fetch)(registrationUrl, {
795
+ method: "POST",
796
+ headers: {
797
+ "Content-Type": "application/json"
798
+ },
799
+ body: JSON.stringify(clientMetadata)
800
+ });
801
+ if (!response.ok) {
802
+ throw await parseErrorResponse(response);
803
+ }
804
+ return OAuthClientInformationFullSchema.parse(await response.json());
805
+ }
806
+ async function auth(provider, options) {
807
+ var _a3, _b3;
808
+ try {
809
+ return await authInternal(provider, options);
810
+ } catch (error) {
811
+ if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
812
+ await ((_a3 = provider.invalidateCredentials) == null ? void 0 : _a3.call(provider, "all"));
813
+ return await authInternal(provider, options);
814
+ } else if (error instanceof InvalidGrantError) {
815
+ await ((_b3 = provider.invalidateCredentials) == null ? void 0 : _b3.call(provider, "tokens"));
816
+ return await authInternal(provider, options);
817
+ }
818
+ throw error;
819
+ }
820
+ }
821
+ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
822
+ const defaultResource = resourceUrlFromServerUrl(serverUrl);
823
+ if (provider.validateResourceURL) {
824
+ return await provider.validateResourceURL(
825
+ defaultResource,
826
+ resourceMetadata == null ? void 0 : resourceMetadata.resource
827
+ );
828
+ }
829
+ if (!resourceMetadata) {
830
+ return void 0;
831
+ }
832
+ if (!checkResourceAllowed({
833
+ requestedResource: defaultResource,
834
+ configuredResource: resourceMetadata.resource
835
+ })) {
836
+ throw new Error(
837
+ `Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`
838
+ );
839
+ }
840
+ return new URL(resourceMetadata.resource);
841
+ }
842
+ async function authInternal(provider, {
843
+ serverUrl,
844
+ authorizationCode,
845
+ scope,
846
+ resourceMetadataUrl,
847
+ fetchFn
848
+ }) {
849
+ let resourceMetadata;
850
+ let authorizationServerUrl;
851
+ try {
852
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(
853
+ serverUrl,
854
+ { resourceMetadataUrl },
855
+ fetchFn
856
+ );
857
+ if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
858
+ authorizationServerUrl = resourceMetadata.authorization_servers[0];
859
+ }
860
+ } catch (e) {
861
+ }
862
+ if (!authorizationServerUrl) {
863
+ authorizationServerUrl = serverUrl;
864
+ }
865
+ const resource = await selectResourceURL(
866
+ serverUrl,
867
+ provider,
868
+ resourceMetadata
869
+ );
870
+ const metadata = await discoverAuthorizationServerMetadata(
871
+ authorizationServerUrl,
872
+ {
873
+ fetchFn
874
+ }
875
+ );
876
+ let clientInformation = await Promise.resolve(provider.clientInformation());
877
+ if (!clientInformation) {
878
+ if (authorizationCode !== void 0) {
879
+ throw new Error(
880
+ "Existing OAuth client information is required when exchanging an authorization code"
881
+ );
882
+ }
883
+ if (!provider.saveClientInformation) {
884
+ throw new Error(
885
+ "OAuth client information must be saveable for dynamic registration"
886
+ );
887
+ }
888
+ const fullInformation = await registerClient(authorizationServerUrl, {
889
+ metadata,
890
+ clientMetadata: provider.clientMetadata,
891
+ fetchFn
892
+ });
893
+ await provider.saveClientInformation(fullInformation);
894
+ clientInformation = fullInformation;
895
+ }
896
+ if (authorizationCode !== void 0) {
897
+ const codeVerifier2 = await provider.codeVerifier();
898
+ const tokens2 = await exchangeAuthorization(authorizationServerUrl, {
899
+ metadata,
900
+ clientInformation,
901
+ authorizationCode,
902
+ codeVerifier: codeVerifier2,
903
+ redirectUri: provider.redirectUrl,
904
+ resource,
905
+ addClientAuthentication: provider.addClientAuthentication,
906
+ fetchFn
907
+ });
908
+ await provider.saveTokens(tokens2);
909
+ return "AUTHORIZED";
910
+ }
911
+ const tokens = await provider.tokens();
912
+ if (tokens == null ? void 0 : tokens.refresh_token) {
913
+ try {
914
+ const newTokens = await refreshAuthorization(authorizationServerUrl, {
915
+ metadata,
916
+ clientInformation,
917
+ refreshToken: tokens.refresh_token,
918
+ resource,
919
+ addClientAuthentication: provider.addClientAuthentication,
920
+ fetchFn
921
+ });
922
+ await provider.saveTokens(newTokens);
923
+ return "AUTHORIZED";
924
+ } catch (error) {
925
+ if (
926
+ // If this is a ServerError, or an unknown type, log it out and try to continue. Otherwise, escalate so we can fix things and retry.
927
+ !(error instanceof MCPClientOAuthError) || error instanceof ServerError
928
+ ) {
929
+ } else {
930
+ throw error;
931
+ }
932
+ }
933
+ }
934
+ const state = provider.state ? await provider.state() : void 0;
935
+ const { authorizationUrl, codeVerifier } = await startAuthorization(
936
+ authorizationServerUrl,
937
+ {
938
+ metadata,
939
+ clientInformation,
940
+ state,
941
+ redirectUrl: provider.redirectUrl,
942
+ scope: scope || provider.clientMetadata.scope,
943
+ resource
944
+ }
945
+ );
946
+ await provider.saveCodeVerifier(codeVerifier);
947
+ await provider.redirectToAuthorization(authorizationUrl);
948
+ return "REDIRECT";
949
+ }
950
+
951
+ // src/tool/mcp-sse-transport.ts
952
+ var SseMCPTransport = class {
953
+ constructor({
954
+ url,
955
+ headers,
956
+ authProvider
957
+ }) {
958
+ this.connected = false;
959
+ this.url = new URL(url);
960
+ this.headers = headers;
961
+ this.authProvider = authProvider;
962
+ }
963
+ async commonHeaders(base) {
964
+ const headers = {
965
+ ...this.headers,
966
+ ...base,
967
+ "mcp-protocol-version": LATEST_PROTOCOL_VERSION
968
+ };
969
+ if (this.authProvider) {
970
+ const tokens = await this.authProvider.tokens();
971
+ if (tokens == null ? void 0 : tokens.access_token) {
972
+ headers["Authorization"] = `Bearer ${tokens.access_token}`;
973
+ }
974
+ }
975
+ return (0, import_provider_utils.withUserAgentSuffix)(
976
+ headers,
977
+ `ai-sdk/${VERSION}`,
978
+ (0, import_provider_utils.getRuntimeEnvironmentUserAgent)()
979
+ );
980
+ }
981
+ async start() {
982
+ return new Promise((resolve, reject) => {
983
+ if (this.connected) {
984
+ return resolve();
985
+ }
986
+ this.abortController = new AbortController();
987
+ const establishConnection = async (triedAuth = false) => {
988
+ var _a3, _b3, _c, _d, _e;
989
+ try {
990
+ const headers = await this.commonHeaders({
991
+ Accept: "text/event-stream"
992
+ });
993
+ const response = await fetch(this.url.href, {
994
+ headers,
995
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
996
+ });
997
+ if (response.status === 401 && this.authProvider && !triedAuth) {
998
+ this.resourceMetadataUrl = extractResourceMetadataUrl(response);
999
+ try {
1000
+ const result = await auth(this.authProvider, {
1001
+ serverUrl: this.url,
1002
+ resourceMetadataUrl: this.resourceMetadataUrl
1003
+ });
1004
+ if (result !== "AUTHORIZED") {
1005
+ const error = new UnauthorizedError();
1006
+ (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);
1007
+ return reject(error);
1008
+ }
1009
+ } catch (error) {
1010
+ (_c = this.onerror) == null ? void 0 : _c.call(this, error);
1011
+ return reject(error);
1012
+ }
1013
+ return establishConnection(true);
1014
+ }
1015
+ if (!response.ok || !response.body) {
1016
+ let errorMessage = `MCP SSE Transport Error: ${response.status} ${response.statusText}`;
1017
+ if (response.status === 405) {
1018
+ errorMessage += ". This server does not support SSE transport. Try using `http` transport instead";
1019
+ }
1020
+ const error = new MCPClientError({
1021
+ message: errorMessage
1022
+ });
1023
+ (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1024
+ return reject(error);
1025
+ }
1026
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils.EventSourceParserStream());
1027
+ const reader = stream.getReader();
1028
+ const processEvents = async () => {
1029
+ var _a4, _b4, _c2;
1030
+ try {
1031
+ while (true) {
1032
+ const { done, value } = await reader.read();
1033
+ if (done) {
1034
+ if (this.connected) {
1035
+ this.connected = false;
1036
+ throw new MCPClientError({
1037
+ message: "MCP SSE Transport Error: Connection closed unexpectedly"
1038
+ });
1039
+ }
1040
+ return;
1041
+ }
1042
+ const { event, data } = value;
1043
+ if (event === "endpoint") {
1044
+ this.endpoint = new URL(data, this.url);
1045
+ if (this.endpoint.origin !== this.url.origin) {
1046
+ throw new MCPClientError({
1047
+ message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${this.endpoint.origin}`
1048
+ });
1049
+ }
1050
+ this.connected = true;
1051
+ resolve();
1052
+ } else if (event === "message") {
1053
+ try {
1054
+ const message = JSONRPCMessageSchema.parse(
1055
+ JSON.parse(data)
1056
+ );
1057
+ (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, message);
1058
+ } catch (error) {
1059
+ const e = new MCPClientError({
1060
+ message: "MCP SSE Transport Error: Failed to parse message",
1061
+ cause: error
1062
+ });
1063
+ (_b4 = this.onerror) == null ? void 0 : _b4.call(this, e);
1064
+ }
1065
+ }
1066
+ }
1067
+ } catch (error) {
1068
+ if (error instanceof Error && error.name === "AbortError") {
1069
+ return;
1070
+ }
1071
+ (_c2 = this.onerror) == null ? void 0 : _c2.call(this, error);
1072
+ reject(error);
1073
+ }
1074
+ };
1075
+ this.sseConnection = {
1076
+ close: () => reader.cancel()
1077
+ };
1078
+ processEvents();
1079
+ } catch (error) {
1080
+ if (error instanceof Error && error.name === "AbortError") {
1081
+ return;
1082
+ }
1083
+ (_e = this.onerror) == null ? void 0 : _e.call(this, error);
1084
+ reject(error);
1085
+ }
1086
+ };
1087
+ void establishConnection();
1088
+ });
1089
+ }
1090
+ async close() {
1091
+ var _a3, _b3, _c;
1092
+ this.connected = false;
1093
+ (_a3 = this.sseConnection) == null ? void 0 : _a3.close();
1094
+ (_b3 = this.abortController) == null ? void 0 : _b3.abort();
1095
+ (_c = this.onclose) == null ? void 0 : _c.call(this);
1096
+ }
1097
+ async send(message) {
1098
+ if (!this.endpoint || !this.connected) {
1099
+ throw new MCPClientError({
1100
+ message: "MCP SSE Transport Error: Not connected"
1101
+ });
1102
+ }
1103
+ const endpoint = this.endpoint;
1104
+ const attempt = async (triedAuth = false) => {
1105
+ var _a3, _b3, _c, _d, _e;
1106
+ try {
1107
+ const headers = await this.commonHeaders({
1108
+ "Content-Type": "application/json"
1109
+ });
1110
+ const init = {
1111
+ method: "POST",
1112
+ headers,
1113
+ body: JSON.stringify(message),
1114
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1115
+ };
1116
+ const response = await fetch(endpoint, init);
1117
+ if (response.status === 401 && this.authProvider && !triedAuth) {
1118
+ this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1119
+ try {
1120
+ const result = await auth(this.authProvider, {
1121
+ serverUrl: this.url,
1122
+ resourceMetadataUrl: this.resourceMetadataUrl
1123
+ });
1124
+ if (result !== "AUTHORIZED") {
1125
+ const error = new UnauthorizedError();
1126
+ (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);
1127
+ return;
1128
+ }
1129
+ } catch (error) {
1130
+ (_c = this.onerror) == null ? void 0 : _c.call(this, error);
1131
+ return;
1132
+ }
1133
+ return attempt(true);
1134
+ }
1135
+ if (!response.ok) {
1136
+ const text = await response.text().catch(() => null);
1137
+ const error = new MCPClientError({
1138
+ message: `MCP SSE Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}`
1139
+ });
1140
+ (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1141
+ return;
1142
+ }
1143
+ } catch (error) {
1144
+ (_e = this.onerror) == null ? void 0 : _e.call(this, error);
1145
+ return;
1146
+ }
1147
+ };
1148
+ await attempt();
1149
+ }
1150
+ };
1151
+
1152
+ // src/tool/mcp-http-transport.ts
1153
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
1154
+ var HttpMCPTransport = class {
1155
+ constructor({
1156
+ url,
1157
+ headers,
1158
+ authProvider
1159
+ }) {
1160
+ this.inboundReconnectAttempts = 0;
1161
+ this.reconnectionOptions = {
1162
+ initialReconnectionDelay: 1e3,
1163
+ maxReconnectionDelay: 3e4,
1164
+ reconnectionDelayGrowFactor: 1.5,
1165
+ maxRetries: 2
1166
+ };
1167
+ this.url = new URL(url);
1168
+ this.headers = headers;
1169
+ this.authProvider = authProvider;
1170
+ }
1171
+ async commonHeaders(base) {
1172
+ const headers = {
1173
+ ...this.headers,
1174
+ ...base,
1175
+ "mcp-protocol-version": LATEST_PROTOCOL_VERSION
1176
+ };
1177
+ if (this.sessionId) {
1178
+ headers["mcp-session-id"] = this.sessionId;
1179
+ }
1180
+ if (this.authProvider) {
1181
+ const tokens = await this.authProvider.tokens();
1182
+ if (tokens == null ? void 0 : tokens.access_token) {
1183
+ headers["Authorization"] = `Bearer ${tokens.access_token}`;
1184
+ }
1185
+ }
1186
+ return (0, import_provider_utils2.withUserAgentSuffix)(
1187
+ headers,
1188
+ `ai-sdk/${VERSION}`,
1189
+ (0, import_provider_utils2.getRuntimeEnvironmentUserAgent)()
1190
+ );
1191
+ }
1192
+ async start() {
1193
+ if (this.abortController) {
1194
+ throw new MCPClientError({
1195
+ message: "MCP HTTP Transport Error: Transport already started. Note: client.connect() calls start() automatically."
1196
+ });
1197
+ }
1198
+ this.abortController = new AbortController();
1199
+ void this.openInboundSse();
1200
+ }
1201
+ async close() {
1202
+ var _a3, _b3, _c;
1203
+ (_a3 = this.inboundSseConnection) == null ? void 0 : _a3.close();
1204
+ try {
1205
+ if (this.sessionId && this.abortController && !this.abortController.signal.aborted) {
1206
+ const headers = await this.commonHeaders({});
1207
+ await fetch(this.url, {
1208
+ method: "DELETE",
1209
+ headers,
1210
+ signal: this.abortController.signal
1211
+ }).catch(() => void 0);
1212
+ }
1213
+ } catch (e) {
1214
+ }
1215
+ (_b3 = this.abortController) == null ? void 0 : _b3.abort();
1216
+ (_c = this.onclose) == null ? void 0 : _c.call(this);
1217
+ }
1218
+ async send(message) {
1219
+ const attempt = async (triedAuth = false) => {
1220
+ var _a3, _b3, _c, _d, _e, _f, _g;
1221
+ try {
1222
+ const headers = await this.commonHeaders({
1223
+ "Content-Type": "application/json",
1224
+ Accept: "application/json, text/event-stream"
1225
+ });
1226
+ const init = {
1227
+ method: "POST",
1228
+ headers,
1229
+ body: JSON.stringify(message),
1230
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1231
+ };
1232
+ const response = await fetch(this.url, init);
1233
+ const sessionId = response.headers.get("mcp-session-id");
1234
+ if (sessionId) {
1235
+ this.sessionId = sessionId;
1236
+ }
1237
+ if (response.status === 401 && this.authProvider && !triedAuth) {
1238
+ this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1239
+ try {
1240
+ const result = await auth(this.authProvider, {
1241
+ serverUrl: this.url,
1242
+ resourceMetadataUrl: this.resourceMetadataUrl
1243
+ });
1244
+ if (result !== "AUTHORIZED") {
1245
+ const error2 = new UnauthorizedError();
1246
+ throw error2;
1247
+ }
1248
+ } catch (error2) {
1249
+ (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error2);
1250
+ throw error2;
1251
+ }
1252
+ return attempt(true);
1253
+ }
1254
+ if (response.status === 202) {
1255
+ if (!this.inboundSseConnection) {
1256
+ void this.openInboundSse();
1257
+ }
1258
+ return;
1259
+ }
1260
+ if (!response.ok) {
1261
+ const text = await response.text().catch(() => null);
1262
+ let errorMessage = `MCP HTTP Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text}`;
1263
+ if (response.status === 404) {
1264
+ errorMessage += ". This server does not support HTTP transport. Try using `sse` transport instead";
1265
+ }
1266
+ const error2 = new MCPClientError({
1267
+ message: errorMessage
1268
+ });
1269
+ (_c = this.onerror) == null ? void 0 : _c.call(this, error2);
1270
+ throw error2;
1271
+ }
1272
+ const contentType = response.headers.get("content-type") || "";
1273
+ if (contentType.includes("application/json")) {
1274
+ const data = await response.json();
1275
+ const messages = Array.isArray(data) ? data.map((m) => JSONRPCMessageSchema.parse(m)) : [JSONRPCMessageSchema.parse(data)];
1276
+ for (const m of messages) (_d = this.onmessage) == null ? void 0 : _d.call(this, m);
1277
+ return;
1278
+ }
1279
+ if (contentType.includes("text/event-stream")) {
1280
+ if (!response.body) {
1281
+ const error2 = new MCPClientError({
1282
+ message: "MCP HTTP Transport Error: text/event-stream response without body"
1283
+ });
1284
+ (_e = this.onerror) == null ? void 0 : _e.call(this, error2);
1285
+ throw error2;
1286
+ }
1287
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils2.EventSourceParserStream());
1288
+ const reader = stream.getReader();
1289
+ const processEvents = async () => {
1290
+ var _a4, _b4, _c2;
1291
+ try {
1292
+ while (true) {
1293
+ const { done, value } = await reader.read();
1294
+ if (done) return;
1295
+ const { event, data } = value;
1296
+ if (event === "message") {
1297
+ try {
1298
+ const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
1299
+ (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, msg);
1300
+ } catch (error2) {
1301
+ const e = new MCPClientError({
1302
+ message: "MCP HTTP Transport Error: Failed to parse message",
1303
+ cause: error2
1304
+ });
1305
+ (_b4 = this.onerror) == null ? void 0 : _b4.call(this, e);
1306
+ }
1307
+ }
1308
+ }
1309
+ } catch (error2) {
1310
+ if (error2 instanceof Error && error2.name === "AbortError") {
1311
+ return;
1312
+ }
1313
+ (_c2 = this.onerror) == null ? void 0 : _c2.call(this, error2);
1314
+ }
1315
+ };
1316
+ processEvents();
1317
+ return;
1318
+ }
1319
+ const error = new MCPClientError({
1320
+ message: `MCP HTTP Transport Error: Unexpected content type: ${contentType}`
1321
+ });
1322
+ (_f = this.onerror) == null ? void 0 : _f.call(this, error);
1323
+ throw error;
1324
+ } catch (error) {
1325
+ (_g = this.onerror) == null ? void 0 : _g.call(this, error);
1326
+ throw error;
1327
+ }
1328
+ };
1329
+ await attempt();
1330
+ }
1331
+ getNextReconnectionDelay(attempt) {
1332
+ const {
1333
+ initialReconnectionDelay,
1334
+ reconnectionDelayGrowFactor,
1335
+ maxReconnectionDelay
1336
+ } = this.reconnectionOptions;
1337
+ return Math.min(
1338
+ initialReconnectionDelay * Math.pow(reconnectionDelayGrowFactor, attempt),
1339
+ maxReconnectionDelay
1340
+ );
1341
+ }
1342
+ scheduleInboundSseReconnection() {
1343
+ var _a3;
1344
+ const { maxRetries } = this.reconnectionOptions;
1345
+ if (maxRetries > 0 && this.inboundReconnectAttempts >= maxRetries) {
1346
+ (_a3 = this.onerror) == null ? void 0 : _a3.call(
1347
+ this,
1348
+ new MCPClientError({
1349
+ message: `MCP HTTP Transport Error: Maximum reconnection attempts (${maxRetries}) exceeded.`
1350
+ })
1351
+ );
1352
+ return;
1353
+ }
1354
+ const delay = this.getNextReconnectionDelay(this.inboundReconnectAttempts);
1355
+ this.inboundReconnectAttempts += 1;
1356
+ setTimeout(async () => {
1357
+ var _a4;
1358
+ if ((_a4 = this.abortController) == null ? void 0 : _a4.signal.aborted) return;
1359
+ await this.openInboundSse(false, this.lastInboundEventId);
1360
+ }, delay);
1361
+ }
1362
+ // Open optional inbound SSE stream; best-effort and resumable
1363
+ async openInboundSse(triedAuth = false, resumeToken) {
1364
+ var _a3, _b3, _c, _d, _e, _f;
1365
+ try {
1366
+ const headers = await this.commonHeaders({
1367
+ Accept: "text/event-stream"
1368
+ });
1369
+ if (resumeToken) {
1370
+ headers["last-event-id"] = resumeToken;
1371
+ }
1372
+ const response = await fetch(this.url.href, {
1373
+ method: "GET",
1374
+ headers,
1375
+ signal: (_a3 = this.abortController) == null ? void 0 : _a3.signal
1376
+ });
1377
+ const sessionId = response.headers.get("mcp-session-id");
1378
+ if (sessionId) {
1379
+ this.sessionId = sessionId;
1380
+ }
1381
+ if (response.status === 401 && this.authProvider && !triedAuth) {
1382
+ this.resourceMetadataUrl = extractResourceMetadataUrl(response);
1383
+ try {
1384
+ const result = await auth(this.authProvider, {
1385
+ serverUrl: this.url,
1386
+ resourceMetadataUrl: this.resourceMetadataUrl
1387
+ });
1388
+ if (result !== "AUTHORIZED") {
1389
+ const error = new UnauthorizedError();
1390
+ (_b3 = this.onerror) == null ? void 0 : _b3.call(this, error);
1391
+ return;
1392
+ }
1393
+ } catch (error) {
1394
+ (_c = this.onerror) == null ? void 0 : _c.call(this, error);
1395
+ return;
1396
+ }
1397
+ return this.openInboundSse(true, resumeToken);
1398
+ }
1399
+ if (response.status === 405) {
1400
+ return;
1401
+ }
1402
+ if (!response.ok || !response.body) {
1403
+ const error = new MCPClientError({
1404
+ message: `MCP HTTP Transport Error: GET SSE failed: ${response.status} ${response.statusText}`
1405
+ });
1406
+ (_d = this.onerror) == null ? void 0 : _d.call(this, error);
1407
+ return;
1408
+ }
1409
+ const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils2.EventSourceParserStream());
1410
+ const reader = stream.getReader();
1411
+ const processEvents = async () => {
1412
+ var _a4, _b4, _c2, _d2;
1413
+ try {
1414
+ while (true) {
1415
+ const { done, value } = await reader.read();
1416
+ if (done) return;
1417
+ const { event, data, id } = value;
1418
+ if (id) {
1419
+ this.lastInboundEventId = id;
1420
+ }
1421
+ if (event === "message") {
1422
+ try {
1423
+ const msg = JSONRPCMessageSchema.parse(JSON.parse(data));
1424
+ (_a4 = this.onmessage) == null ? void 0 : _a4.call(this, msg);
1425
+ } catch (error) {
1426
+ const e = new MCPClientError({
1427
+ message: "MCP HTTP Transport Error: Failed to parse message",
1428
+ cause: error
1429
+ });
1430
+ (_b4 = this.onerror) == null ? void 0 : _b4.call(this, e);
1431
+ }
1432
+ }
1433
+ }
1434
+ } catch (error) {
1435
+ if (error instanceof Error && error.name === "AbortError") {
1436
+ return;
1437
+ }
1438
+ (_c2 = this.onerror) == null ? void 0 : _c2.call(this, error);
1439
+ if (!((_d2 = this.abortController) == null ? void 0 : _d2.signal.aborted)) {
1440
+ this.scheduleInboundSseReconnection();
1441
+ }
1442
+ }
1443
+ };
1444
+ this.inboundSseConnection = {
1445
+ close: () => reader.cancel()
1446
+ };
1447
+ this.inboundReconnectAttempts = 0;
1448
+ processEvents();
1449
+ } catch (error) {
1450
+ if (error instanceof Error && error.name === "AbortError") {
1451
+ return;
1452
+ }
1453
+ (_e = this.onerror) == null ? void 0 : _e.call(this, error);
1454
+ if (!((_f = this.abortController) == null ? void 0 : _f.signal.aborted)) {
1455
+ this.scheduleInboundSseReconnection();
1456
+ }
1457
+ }
1458
+ }
1459
+ };
1460
+
1461
+ // src/tool/mcp-transport.ts
1462
+ function createMcpTransport(config) {
1463
+ switch (config.type) {
1464
+ case "sse":
1465
+ return new SseMCPTransport(config);
1466
+ case "http":
1467
+ return new HttpMCPTransport(config);
1468
+ default:
1469
+ throw new MCPClientError({
1470
+ message: "Unsupported or invalid transport configuration. If you are using a custom transport, make sure it implements the MCPTransport interface."
1471
+ });
1472
+ }
1473
+ }
1474
+ function isCustomMcpTransport(transport) {
1475
+ return "start" in transport && typeof transport.start === "function" && "send" in transport && typeof transport.send === "function" && "close" in transport && typeof transport.close === "function";
1476
+ }
1477
+
1478
+ // src/tool/mcp-client.ts
1479
+ var CLIENT_VERSION = "1.0.0";
1480
+ async function createMCPClient(config) {
1481
+ const client = new DefaultMCPClient(config);
1482
+ await client.init();
1483
+ return client;
1484
+ }
1485
+ var DefaultMCPClient = class {
1486
+ constructor({
1487
+ transport: transportConfig,
1488
+ name: name3 = "ai-sdk-mcp-client",
1489
+ onUncaughtError
1490
+ }) {
1491
+ this.requestMessageId = 0;
1492
+ this.responseHandlers = /* @__PURE__ */ new Map();
1493
+ this.serverCapabilities = {};
1494
+ this.isClosed = true;
1495
+ this.onUncaughtError = onUncaughtError;
1496
+ if (isCustomMcpTransport(transportConfig)) {
1497
+ this.transport = transportConfig;
1498
+ } else {
1499
+ this.transport = createMcpTransport(transportConfig);
1500
+ }
1501
+ this.transport.onclose = () => this.onClose();
1502
+ this.transport.onerror = (error) => this.onError(error);
1503
+ this.transport.onmessage = (message) => {
1504
+ if ("method" in message) {
1505
+ this.onError(
1506
+ new MCPClientError({
1507
+ message: "Unsupported message type"
1508
+ })
1509
+ );
1510
+ return;
1511
+ }
1512
+ this.onResponse(message);
1513
+ };
1514
+ this.clientInfo = {
1515
+ name: name3,
1516
+ version: CLIENT_VERSION
1517
+ };
1518
+ }
1519
+ async init() {
1520
+ try {
1521
+ await this.transport.start();
1522
+ this.isClosed = false;
1523
+ const result = await this.request({
1524
+ request: {
1525
+ method: "initialize",
1526
+ params: {
1527
+ protocolVersion: LATEST_PROTOCOL_VERSION,
1528
+ capabilities: {},
1529
+ clientInfo: this.clientInfo
1530
+ }
1531
+ },
1532
+ resultSchema: InitializeResultSchema
1533
+ });
1534
+ if (result === void 0) {
1535
+ throw new MCPClientError({
1536
+ message: "Server sent invalid initialize result"
1537
+ });
1538
+ }
1539
+ if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
1540
+ throw new MCPClientError({
1541
+ message: `Server's protocol version is not supported: ${result.protocolVersion}`
1542
+ });
1543
+ }
1544
+ this.serverCapabilities = result.capabilities;
1545
+ await this.notification({
1546
+ method: "notifications/initialized"
1547
+ });
1548
+ return this;
1549
+ } catch (error) {
1550
+ await this.close();
1551
+ throw error;
1552
+ }
1553
+ }
1554
+ async close() {
1555
+ var _a3;
1556
+ if (this.isClosed) return;
1557
+ await ((_a3 = this.transport) == null ? void 0 : _a3.close());
1558
+ this.onClose();
1559
+ }
1560
+ assertCapability(method) {
1561
+ switch (method) {
1562
+ case "initialize":
1563
+ break;
1564
+ case "tools/list":
1565
+ case "tools/call":
1566
+ if (!this.serverCapabilities.tools) {
1567
+ throw new MCPClientError({
1568
+ message: `Server does not support tools`
1569
+ });
1570
+ }
1571
+ break;
1572
+ default:
1573
+ throw new MCPClientError({
1574
+ message: `Unsupported method: ${method}`
1575
+ });
1576
+ }
1577
+ }
1578
+ async request({
1579
+ request,
1580
+ resultSchema,
1581
+ options
1582
+ }) {
1583
+ return new Promise((resolve, reject) => {
1584
+ if (this.isClosed) {
1585
+ return reject(
1586
+ new MCPClientError({
1587
+ message: "Attempted to send a request from a closed client"
1588
+ })
1589
+ );
1590
+ }
1591
+ this.assertCapability(request.method);
1592
+ const signal = options == null ? void 0 : options.signal;
1593
+ signal == null ? void 0 : signal.throwIfAborted();
1594
+ const messageId = this.requestMessageId++;
1595
+ const jsonrpcRequest = {
1596
+ ...request,
1597
+ jsonrpc: "2.0",
1598
+ id: messageId
1599
+ };
1600
+ const cleanup = () => {
1601
+ this.responseHandlers.delete(messageId);
1602
+ };
1603
+ this.responseHandlers.set(messageId, (response) => {
1604
+ if (signal == null ? void 0 : signal.aborted) {
1605
+ return reject(
1606
+ new MCPClientError({
1607
+ message: "Request was aborted",
1608
+ cause: signal.reason
1609
+ })
1610
+ );
1611
+ }
1612
+ if (response instanceof Error) {
1613
+ return reject(response);
1614
+ }
1615
+ try {
1616
+ const result = resultSchema.parse(response.result);
1617
+ resolve(result);
1618
+ } catch (error) {
1619
+ const parseError = new MCPClientError({
1620
+ message: "Failed to parse server response",
1621
+ cause: error
1622
+ });
1623
+ reject(parseError);
1624
+ }
1625
+ });
1626
+ this.transport.send(jsonrpcRequest).catch((error) => {
1627
+ cleanup();
1628
+ reject(error);
1629
+ });
1630
+ });
1631
+ }
1632
+ async listTools({
1633
+ params,
1634
+ options
1635
+ } = {}) {
1636
+ try {
1637
+ return this.request({
1638
+ request: { method: "tools/list", params },
1639
+ resultSchema: ListToolsResultSchema,
1640
+ options
1641
+ });
1642
+ } catch (error) {
1643
+ throw error;
1644
+ }
1645
+ }
1646
+ async callTool({
1647
+ name: name3,
1648
+ args,
1649
+ options
1650
+ }) {
1651
+ try {
1652
+ return this.request({
1653
+ request: { method: "tools/call", params: { name: name3, arguments: args } },
1654
+ resultSchema: CallToolResultSchema,
1655
+ options: {
1656
+ signal: options == null ? void 0 : options.abortSignal
1657
+ }
1658
+ });
1659
+ } catch (error) {
1660
+ throw error;
1661
+ }
1662
+ }
1663
+ async notification(notification) {
1664
+ const jsonrpcNotification = {
1665
+ ...notification,
1666
+ jsonrpc: "2.0"
1667
+ };
1668
+ await this.transport.send(jsonrpcNotification);
1669
+ }
1670
+ /**
1671
+ * Returns a set of AI SDK tools from the MCP server
1672
+ * @returns A record of tool names to their implementations
1673
+ */
1674
+ async tools({
1675
+ schemas = "automatic"
1676
+ } = {}) {
1677
+ var _a3;
1678
+ const tools = {};
1679
+ try {
1680
+ const listToolsResult = await this.listTools();
1681
+ for (const { name: name3, description, inputSchema } of listToolsResult.tools) {
1682
+ if (schemas !== "automatic" && !(name3 in schemas)) {
1683
+ continue;
1684
+ }
1685
+ const self = this;
1686
+ const execute = async (args, options) => {
1687
+ var _a4;
1688
+ (_a4 = options == null ? void 0 : options.abortSignal) == null ? void 0 : _a4.throwIfAborted();
1689
+ return self.callTool({ name: name3, args, options });
1690
+ };
1691
+ const toolWithExecute = schemas === "automatic" ? (0, import_provider_utils3.dynamicTool)({
1692
+ description,
1693
+ inputSchema: (0, import_provider_utils3.jsonSchema)({
1694
+ ...inputSchema,
1695
+ properties: (_a3 = inputSchema.properties) != null ? _a3 : {},
1696
+ additionalProperties: false
1697
+ }),
1698
+ execute
1699
+ }) : (0, import_provider_utils3.tool)({
1700
+ description,
1701
+ inputSchema: schemas[name3].inputSchema,
1702
+ execute
1703
+ });
1704
+ tools[name3] = toolWithExecute;
1705
+ }
1706
+ return tools;
1707
+ } catch (error) {
1708
+ throw error;
1709
+ }
1710
+ }
1711
+ onClose() {
1712
+ if (this.isClosed) return;
1713
+ this.isClosed = true;
1714
+ const error = new MCPClientError({
1715
+ message: "Connection closed"
1716
+ });
1717
+ for (const handler of this.responseHandlers.values()) {
1718
+ handler(error);
1719
+ }
1720
+ this.responseHandlers.clear();
1721
+ }
1722
+ onError(error) {
1723
+ if (this.onUncaughtError) {
1724
+ this.onUncaughtError(error);
1725
+ }
1726
+ }
1727
+ onResponse(response) {
1728
+ const messageId = Number(response.id);
1729
+ const handler = this.responseHandlers.get(messageId);
1730
+ if (handler === void 0) {
1731
+ throw new MCPClientError({
1732
+ message: `Protocol error: Received a response for an unknown message ID: ${JSON.stringify(
1733
+ response
1734
+ )}`
1735
+ });
1736
+ }
1737
+ this.responseHandlers.delete(messageId);
1738
+ handler(
1739
+ "result" in response ? response : new MCPClientError({
1740
+ message: response.error.message,
1741
+ code: response.error.code,
1742
+ data: response.error.data,
1743
+ cause: response.error
1744
+ })
1745
+ );
1746
+ }
1747
+ };
1748
+ // Annotate the CommonJS export names for ESM import in node:
1749
+ 0 && (module.exports = {
1750
+ UnauthorizedError,
1751
+ auth,
1752
+ experimental_createMCPClient
1753
+ });
1754
+ //# sourceMappingURL=index.js.map