@pablopunk/tau 0.0.0-stage → 0.1.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.
Files changed (69) hide show
  1. package/dist/auth-storage-Dk3CUY3q.js +1814 -0
  2. package/dist/bin.js +23 -0
  3. package/dist/cli-entry-DcDpQ30L.js +13 -0
  4. package/dist/client-C91-b2CL.js +1 -0
  5. package/dist/client-y2WkNuZj.js +7977 -0
  6. package/dist/dist-BFP19NOO.js +432 -0
  7. package/dist/dist-Bh1bQHZA.js +38890 -0
  8. package/dist/dist-Cq73_r65.js +3 -0
  9. package/dist/esm-CMGh_WhC.js +9446 -0
  10. package/dist/execute-BeGXhU1O.js +1757 -0
  11. package/dist/fake-claude-connectors-DSP9UC8d.js +1 -0
  12. package/dist/fake-claude-connectors-sDLeP10T.js +107 -0
  13. package/dist/fake-claude-sdk-CvqW_1iQ.js +571 -0
  14. package/dist/fake-claude-thread-script-2iHHwUZM.js +48 -0
  15. package/dist/last-exit-write-ksHeHGrC.js +9 -0
  16. package/dist/latest-version-di9hD7cY.js +106 -0
  17. package/dist/lib-DIX7q_HJ.js +1460 -0
  18. package/dist/machines-behind-BjGgmSs_.js +257 -0
  19. package/dist/main-D-Tg9b5Y.js +1610 -0
  20. package/dist/manager-B_WHbb1U.js +589 -0
  21. package/dist/names-cTrEXB6w.js +35 -0
  22. package/dist/node-BpwblPFP.js +56269 -0
  23. package/dist/pdfjs-nTcHjDPT.js +69856 -0
  24. package/dist/photon_rs-DBr7W_rK.js +4252 -0
  25. package/dist/promise.try-CAAOYvMP.js +1426 -0
  26. package/dist/readability-DsDNO63a.js +1670 -0
  27. package/dist/real-deps-f96UmLBz.js +89 -0
  28. package/dist/rolldown-runtime-1p2KPIdQ.js +44 -0
  29. package/dist/runtime-i-oEtgAl.js +2721 -0
  30. package/dist/sdk-missing-CHbVbY1G.js +10 -0
  31. package/dist/sdk-port-BGw9ORUR.js +215 -0
  32. package/dist/serve-Cmy0rUWr.js +2932 -0
  33. package/dist/serve-Dmzn5V0l.js +1 -0
  34. package/dist/service-command-C74K0saj.js +34 -0
  35. package/dist/service-command-DqcstJ8e.js +1 -0
  36. package/dist/shell-CQa4e7rx.js +643 -0
  37. package/dist/skills/builtin/tau/SKILL.md +51 -0
  38. package/dist/src-DO9LUlhi.js +44088 -0
  39. package/dist/streamableHttp-BBaRYV9h.js +1 -0
  40. package/dist/streamableHttp-DPAoMlJd.js +1931 -0
  41. package/dist/tool-DBZK2lci.js +14335 -0
  42. package/dist/tool-server-BjP37EJg.js +40 -0
  43. package/dist/turndown.cjs-Bo1xLg2S.js +15620 -0
  44. package/dist/turndown.cjs-jpUF50AR.js +3 -0
  45. package/dist/types-C4M3CRp2.js +7592 -0
  46. package/dist/undici-8cI97lnP.js +27110 -0
  47. package/dist/wait-for-lock-B1Qx8GWg.js +1 -0
  48. package/dist/wait-for-lock-CrSl2mi1.js +25 -0
  49. package/dist/watchdog.js +47 -0
  50. package/dist/web/dist/assets/addon-fit-DIOBYJe3.js +1 -0
  51. package/dist/web/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  52. package/dist/web/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  53. package/dist/web/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  54. package/dist/web/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  55. package/dist/web/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  56. package/dist/web/dist/assets/index-BktLKZHR.js +108 -0
  57. package/dist/web/dist/assets/index-D_Aa3Oou.css +2 -0
  58. package/dist/web/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  59. package/dist/web/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  60. package/dist/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  61. package/dist/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  62. package/dist/web/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  63. package/dist/web/dist/assets/wght-DMLdVLkb.css +1 -0
  64. package/dist/web/dist/assets/xterm-BrP-ENHg.css +1 -0
  65. package/dist/web/dist/assets/xterm-CerOhKYV.js +16 -0
  66. package/dist/web/dist/favicon.svg +14 -0
  67. package/dist/web/dist/index.html +25 -0
  68. package/package.json +53 -4
  69. package/README.md +0 -3
@@ -0,0 +1,1931 @@
1
+ import { o as __toESM, t as __commonJSMin } from "./rolldown-runtime-1p2KPIdQ.js";
2
+ import { $ as object, B as isInitializedNotification, J as array, K as ZodNumber, Q as number$1, U as isJSONRPCRequest, W as isJSONRPCResultResponse, X as literal, Y as boolean, Z as looseObject, b as JSONRPCMessageSchema, et as string, it as NEVER, nt as _coercedNumber, q as any, tt as url, x as LATEST_PROTOCOL_VERSION } from "./types-C4M3CRp2.js";
3
+ //#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/compat.js
4
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5
+ const ZodIssueCode = {
6
+ invalid_type: "invalid_type",
7
+ too_big: "too_big",
8
+ too_small: "too_small",
9
+ invalid_format: "invalid_format",
10
+ not_multiple_of: "not_multiple_of",
11
+ unrecognized_keys: "unrecognized_keys",
12
+ invalid_union: "invalid_union",
13
+ invalid_key: "invalid_key",
14
+ invalid_element: "invalid_element",
15
+ invalid_value: "invalid_value",
16
+ custom: "custom"
17
+ };
18
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
19
+ var ZodFirstPartyTypeKind;
20
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
21
+ //#endregion
22
+ //#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/coerce.js
23
+ function number(params) {
24
+ return _coercedNumber(ZodNumber, params);
25
+ }
26
+ /*!
27
+ * content-type
28
+ * Copyright(c) 2015 Douglas Christopher Wilson
29
+ * MIT Licensed
30
+ */
31
+ //#endregion
32
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/mediaType.js
33
+ var import_content_type = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports) => {
34
+ /**
35
+ * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
36
+ *
37
+ * parameter = token "=" ( token / quoted-string )
38
+ * token = 1*tchar
39
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
40
+ * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
41
+ * / DIGIT / ALPHA
42
+ * ; any VCHAR, except delimiters
43
+ * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
44
+ * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
45
+ * obs-text = %x80-FF
46
+ * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
47
+ */
48
+ var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g;
49
+ /**
50
+ * RegExp to match quoted-pair in RFC 7230 sec 3.2.6
51
+ *
52
+ * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
53
+ * obs-text = %x80-FF
54
+ */
55
+ var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g;
56
+ /**
57
+ * RegExp to match type in RFC 7231 sec 3.1.1.1
58
+ *
59
+ * media-type = type "/" subtype
60
+ * type = token
61
+ * subtype = token
62
+ */
63
+ var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
64
+ exports.parse = parse;
65
+ /**
66
+ * Parse media type to object.
67
+ *
68
+ * @param {string|object} string
69
+ * @return {Object}
70
+ * @public
71
+ */
72
+ function parse(string) {
73
+ if (!string) throw new TypeError("argument string is required");
74
+ var header = typeof string === "object" ? getcontenttype(string) : string;
75
+ if (typeof header !== "string") throw new TypeError("argument string is required to be a string");
76
+ var index = header.indexOf(";");
77
+ var type = index !== -1 ? header.slice(0, index).trim() : header.trim();
78
+ if (!TYPE_REGEXP.test(type)) throw new TypeError("invalid media type");
79
+ var obj = new ContentType(type.toLowerCase());
80
+ if (index !== -1) {
81
+ var key;
82
+ var match;
83
+ var value;
84
+ PARAM_REGEXP.lastIndex = index;
85
+ while (match = PARAM_REGEXP.exec(header)) {
86
+ if (match.index !== index) throw new TypeError("invalid parameter format");
87
+ index += match[0].length;
88
+ key = match[1].toLowerCase();
89
+ value = match[2];
90
+ if (value.charCodeAt(0) === 34) {
91
+ value = value.slice(1, -1);
92
+ if (value.indexOf("\\") !== -1) value = value.replace(QESC_REGEXP, "$1");
93
+ }
94
+ obj.parameters[key] = value;
95
+ }
96
+ if (index !== header.length) throw new TypeError("invalid parameter format");
97
+ }
98
+ return obj;
99
+ }
100
+ /**
101
+ * Get content-type from req/res objects.
102
+ *
103
+ * @param {object}
104
+ * @return {Object}
105
+ * @private
106
+ */
107
+ function getcontenttype(obj) {
108
+ var header;
109
+ if (typeof obj.getHeader === "function") header = obj.getHeader("content-type");
110
+ else if (typeof obj.headers === "object") header = obj.headers && obj.headers["content-type"];
111
+ if (typeof header !== "string") throw new TypeError("content-type header is missing from object");
112
+ return header;
113
+ }
114
+ /**
115
+ * Class to represent a content type.
116
+ * @private
117
+ */
118
+ function ContentType(type) {
119
+ this.parameters = Object.create(null);
120
+ this.type = type;
121
+ }
122
+ })))(), 1);
123
+ /**
124
+ * Extracts the media type (the lowercased `type/subtype` pair, without
125
+ * parameters) from a raw `Content-Type` header value, or `undefined` when the
126
+ * header is missing or empty.
127
+ *
128
+ * Content-Type comparisons must use the parsed media type, never a substring
129
+ * search of the raw header: a value like `text/plain; a=application/json`
130
+ * contains the substring `application/json` but its media type is
131
+ * `text/plain`, and case variants or parameters make naive string comparison
132
+ * wrong in both directions.
133
+ *
134
+ * "Essence" is the WHATWG MIME Sniffing standard's term for the bare
135
+ * `type/subtype` pair (https://mimesniff.spec.whatwg.org/#mime-type-essence);
136
+ * the Fetch standard's request classification is defined against it
137
+ * (https://fetch.spec.whatwg.org/#cors-safelisted-request-header).
138
+ *
139
+ * Parsing is RFC 9110 (`content-type` package) first. When the parameter
140
+ * section is malformed (`application/json;`, `application/json; charset=`),
141
+ * browsers and most HTTP stacks still derive the media type from the segment
142
+ * before the first `;` — the fallback matches that widely-implemented
143
+ * behavior, so a header whose media type is unambiguous is not rejected for
144
+ * a sloppy parameter section.
145
+ */
146
+ function mediaTypeEssence(header) {
147
+ if (!header) return;
148
+ try {
149
+ return import_content_type.parse(header).type;
150
+ } catch {
151
+ const essence = (header.split(";", 1)[0] ?? "").trim().toLowerCase();
152
+ if (essence === "" || header.slice(essence.length).includes(",")) return;
153
+ return essence;
154
+ }
155
+ }
156
+ //#endregion
157
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
158
+ /**
159
+ * Normalizes HeadersInit to a plain Record<string, string> for manipulation.
160
+ * Handles Headers objects, arrays of tuples, and plain objects.
161
+ */
162
+ function normalizeHeaders(headers) {
163
+ if (!headers) return {};
164
+ if (headers instanceof Headers) return Object.fromEntries(headers.entries());
165
+ if (Array.isArray(headers)) return Object.fromEntries(headers);
166
+ return { ...headers };
167
+ }
168
+ /**
169
+ * Creates a fetch function that includes base RequestInit options.
170
+ * This ensures requests inherit settings like credentials, mode, headers, etc. from the base init.
171
+ *
172
+ * @param baseFetch - The base fetch function to wrap (defaults to global fetch)
173
+ * @param baseInit - The base RequestInit to merge with each request
174
+ * @returns A wrapped fetch function that merges base options with call-specific options
175
+ */
176
+ function createFetchWithInit(baseFetch = fetch, baseInit) {
177
+ if (!baseInit) return baseFetch;
178
+ return async (url, init) => {
179
+ return baseFetch(url, {
180
+ ...baseInit,
181
+ ...init,
182
+ headers: init?.headers ? {
183
+ ...normalizeHeaders(baseInit.headers),
184
+ ...normalizeHeaders(init.headers)
185
+ } : baseInit.headers
186
+ });
187
+ };
188
+ }
189
+ const MAX_REDIRECTS = 5;
190
+ const REDIRECT_STATUSES = [
191
+ 301,
192
+ 302,
193
+ 303,
194
+ 307,
195
+ 308
196
+ ];
197
+ /** @internal Whether `to` has the scheme, host and port of `from`, or is its https form with both on default ports. */
198
+ function isWithinOrigin(from, to) {
199
+ if (from.protocol === to.protocol && from.hostname === to.hostname && from.port === to.port) return true;
200
+ return from.hostname === to.hostname && from.protocol === "http:" && from.port === "" && to.protocol === "https:" && to.port === "";
201
+ }
202
+ function redirectTarget(response, requestUrl) {
203
+ const location = REDIRECT_STATUSES.includes(response.status) ? response.headers.get("location") : null;
204
+ try {
205
+ return location ? new URL(location, requestUrl) : void 0;
206
+ } catch {
207
+ return;
208
+ }
209
+ }
210
+ /** @internal Follows the redirect in `response` while it stays within the origin of `url`; undefined when `response` is to be used as is. */
211
+ function followWithinOrigin(baseFetch, url, init, response, followed = 0) {
212
+ const target = redirectTarget(response, url);
213
+ const keepsMethod = response.status === 307 || response.status === 308 || (init?.method ?? "GET").toUpperCase() === "GET";
214
+ if (!target || followed === MAX_REDIRECTS || !keepsMethod) return;
215
+ const from = new URL(url);
216
+ if ((target.username || target.password) && (target.username !== from.username || target.password !== from.password) || !isWithinOrigin(from, target)) return;
217
+ return Promise.resolve(response.body?.cancel()).then(() => baseFetch(target, {
218
+ ...init,
219
+ redirect: "manual"
220
+ })).then((next) => followWithinOrigin(baseFetch, target, init, next, followed + 1) ?? next);
221
+ }
222
+ const followingFetches = /* @__PURE__ */ new WeakSet();
223
+ /** @internal Wraps a fetch for `redirectPolicy: 'follow'`: `fetchWithinOrigin` returns the result as it is, so redirects are left to the fetch. */
224
+ function fetchLeavingRedirects(baseFetch) {
225
+ const following = (url, init) => (baseFetch ?? fetch)(url, init);
226
+ followingFetches.add(following);
227
+ return following;
228
+ }
229
+ /** @internal Wraps a fetch so it follows a redirect only within the request's origin; any other redirect response is returned as is. */
230
+ function fetchWithinOrigin(baseFetch = fetch) {
231
+ if (followingFetches.has(baseFetch)) return baseFetch;
232
+ return (url, init) => {
233
+ if (init?.redirect === "error" || init?.redirect === "manual") return baseFetch(url, init);
234
+ return Promise.resolve(baseFetch(url, {
235
+ ...init,
236
+ redirect: "manual"
237
+ })).then((response) => followWithinOrigin(baseFetch, url, init, response) ?? response);
238
+ };
239
+ }
240
+ /** @internal Describes a redirect that `fetchWithinOrigin` returned unfollowed, naming its target without userinfo, query or fragment. */
241
+ function unfollowedRedirect(response, requestUrl) {
242
+ if (response.type === "opaqueredirect") return "Redirect not followed: this runtime does not expose the redirect target";
243
+ const from = response.url || requestUrl;
244
+ const target = redirectTarget(response, from);
245
+ if (!target) return;
246
+ target.username = target.password = target.search = target.hash = "";
247
+ if (target.protocol === "http:" && new URL(from).protocol === "https:") {
248
+ target.protocol = "https:";
249
+ return `Redirect to plain http not followed; try ${target.href} instead`;
250
+ }
251
+ return `Redirect to ${target.href} not followed`;
252
+ }
253
+ //#endregion
254
+ //#region ../../node_modules/.pnpm/pkce-challenge@5.0.1/node_modules/pkce-challenge/dist/index.node.js
255
+ let crypto;
256
+ crypto = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m) => m.webcrypto);
257
+ /**
258
+ * Creates an array of length `size` of random bytes
259
+ * @param size
260
+ * @returns Array of random ints (0 to 255)
261
+ */
262
+ async function getRandomValues(size) {
263
+ return (await crypto).getRandomValues(new Uint8Array(size));
264
+ }
265
+ /** Generate cryptographically strong random string
266
+ * @param size The desired length of the string
267
+ * @returns The random string
268
+ */
269
+ async function random(size) {
270
+ const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
271
+ const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % 66;
272
+ let result = "";
273
+ while (result.length < size) {
274
+ const randomBytes = await getRandomValues(size - result.length);
275
+ for (const randomByte of randomBytes) if (randomByte < evenDistCutoff) result += mask[randomByte % 66];
276
+ }
277
+ return result;
278
+ }
279
+ /** Generate a PKCE challenge verifier
280
+ * @param length Length of the verifier
281
+ * @returns A random verifier `length` characters long
282
+ */
283
+ async function generateVerifier(length) {
284
+ return await random(length);
285
+ }
286
+ /** Generate a PKCE code challenge from a code verifier
287
+ * @param code_verifier
288
+ * @returns The base64 url encoded code challenge
289
+ */
290
+ async function generateChallenge(code_verifier) {
291
+ const buffer = await (await crypto).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
292
+ return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
293
+ }
294
+ /** Generate a PKCE challenge pair
295
+ * @param length Length of the verifer (between 43-128). Defaults to 43.
296
+ * @returns PKCE challenge pair
297
+ */
298
+ async function pkceChallenge(length) {
299
+ if (!length) length = 43;
300
+ if (length < 43 || length > 128) throw `Expected a length between 43 and 128. Received ${length}.`;
301
+ const verifier = await generateVerifier(length);
302
+ return {
303
+ code_verifier: verifier,
304
+ code_challenge: await generateChallenge(verifier)
305
+ };
306
+ }
307
+ //#endregion
308
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
309
+ /**
310
+ * Reusable URL validation that disallows javascript: scheme
311
+ */
312
+ const SafeUrlSchema = url().superRefine((val, ctx) => {
313
+ if (!URL.canParse(val)) {
314
+ ctx.addIssue({
315
+ code: ZodIssueCode.custom,
316
+ message: "URL must be parseable",
317
+ fatal: true
318
+ });
319
+ return NEVER;
320
+ }
321
+ }).refine((url) => {
322
+ const u = new URL(url);
323
+ return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
324
+ }, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
325
+ /**
326
+ * RFC 9728 OAuth Protected Resource Metadata
327
+ */
328
+ const OAuthProtectedResourceMetadataSchema = looseObject({
329
+ resource: string().url(),
330
+ authorization_servers: array(SafeUrlSchema).optional(),
331
+ jwks_uri: string().url().optional(),
332
+ scopes_supported: array(string()).optional(),
333
+ bearer_methods_supported: array(string()).optional(),
334
+ resource_signing_alg_values_supported: array(string()).optional(),
335
+ resource_name: string().optional(),
336
+ resource_documentation: string().optional(),
337
+ resource_policy_uri: string().url().optional(),
338
+ resource_tos_uri: string().url().optional(),
339
+ tls_client_certificate_bound_access_tokens: boolean().optional(),
340
+ authorization_details_types_supported: array(string()).optional(),
341
+ dpop_signing_alg_values_supported: array(string()).optional(),
342
+ dpop_bound_access_tokens_required: boolean().optional()
343
+ });
344
+ /**
345
+ * RFC 8414 OAuth 2.0 Authorization Server Metadata
346
+ */
347
+ const OAuthMetadataSchema = looseObject({
348
+ issuer: string(),
349
+ authorization_endpoint: SafeUrlSchema,
350
+ token_endpoint: SafeUrlSchema,
351
+ registration_endpoint: SafeUrlSchema.optional(),
352
+ scopes_supported: array(string()).optional(),
353
+ response_types_supported: array(string()),
354
+ response_modes_supported: array(string()).optional(),
355
+ grant_types_supported: array(string()).optional(),
356
+ token_endpoint_auth_methods_supported: array(string()).optional(),
357
+ token_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
358
+ service_documentation: SafeUrlSchema.optional(),
359
+ revocation_endpoint: SafeUrlSchema.optional(),
360
+ revocation_endpoint_auth_methods_supported: array(string()).optional(),
361
+ revocation_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
362
+ introspection_endpoint: string().optional(),
363
+ introspection_endpoint_auth_methods_supported: array(string()).optional(),
364
+ introspection_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
365
+ code_challenge_methods_supported: array(string()).optional(),
366
+ client_id_metadata_document_supported: boolean().optional()
367
+ });
368
+ /**
369
+ * OpenID Connect Discovery 1.0 Provider Metadata
370
+ * see: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
371
+ */
372
+ const OpenIdProviderMetadataSchema = looseObject({
373
+ issuer: string(),
374
+ authorization_endpoint: SafeUrlSchema,
375
+ token_endpoint: SafeUrlSchema,
376
+ userinfo_endpoint: SafeUrlSchema.optional(),
377
+ jwks_uri: SafeUrlSchema,
378
+ registration_endpoint: SafeUrlSchema.optional(),
379
+ scopes_supported: array(string()).optional(),
380
+ response_types_supported: array(string()),
381
+ response_modes_supported: array(string()).optional(),
382
+ grant_types_supported: array(string()).optional(),
383
+ acr_values_supported: array(string()).optional(),
384
+ subject_types_supported: array(string()),
385
+ id_token_signing_alg_values_supported: array(string()),
386
+ id_token_encryption_alg_values_supported: array(string()).optional(),
387
+ id_token_encryption_enc_values_supported: array(string()).optional(),
388
+ userinfo_signing_alg_values_supported: array(string()).optional(),
389
+ userinfo_encryption_alg_values_supported: array(string()).optional(),
390
+ userinfo_encryption_enc_values_supported: array(string()).optional(),
391
+ request_object_signing_alg_values_supported: array(string()).optional(),
392
+ request_object_encryption_alg_values_supported: array(string()).optional(),
393
+ request_object_encryption_enc_values_supported: array(string()).optional(),
394
+ token_endpoint_auth_methods_supported: array(string()).optional(),
395
+ token_endpoint_auth_signing_alg_values_supported: array(string()).optional(),
396
+ display_values_supported: array(string()).optional(),
397
+ claim_types_supported: array(string()).optional(),
398
+ claims_supported: array(string()).optional(),
399
+ service_documentation: string().optional(),
400
+ claims_locales_supported: array(string()).optional(),
401
+ ui_locales_supported: array(string()).optional(),
402
+ claims_parameter_supported: boolean().optional(),
403
+ request_parameter_supported: boolean().optional(),
404
+ request_uri_parameter_supported: boolean().optional(),
405
+ require_request_uri_registration: boolean().optional(),
406
+ op_policy_uri: SafeUrlSchema.optional(),
407
+ op_tos_uri: SafeUrlSchema.optional(),
408
+ client_id_metadata_document_supported: boolean().optional()
409
+ });
410
+ /**
411
+ * OpenID Connect Discovery metadata that may include OAuth 2.0 fields
412
+ * This schema represents the real-world scenario where OIDC providers
413
+ * return a mix of OpenID Connect and OAuth 2.0 metadata fields
414
+ */
415
+ const OpenIdProviderDiscoveryMetadataSchema = object({
416
+ ...OpenIdProviderMetadataSchema.shape,
417
+ ...OAuthMetadataSchema.pick({ code_challenge_methods_supported: true }).shape
418
+ });
419
+ /**
420
+ * OAuth 2.1 token response
421
+ */
422
+ const OAuthTokensSchema = object({
423
+ access_token: string(),
424
+ id_token: string().optional(),
425
+ token_type: string(),
426
+ expires_in: number().optional(),
427
+ scope: string().optional(),
428
+ refresh_token: string().optional(),
429
+ /**
430
+ * Not part of the wire format: the authorization server this value was obtained from, added by
431
+ * the client's `auth()` before it is stored and compared when it is read back.
432
+ */
433
+ issuer: string().optional().catch(void 0)
434
+ }).strip();
435
+ /**
436
+ * OAuth 2.1 error response
437
+ */
438
+ const OAuthErrorResponseSchema = object({
439
+ error: string(),
440
+ error_description: string().optional(),
441
+ error_uri: string().optional()
442
+ });
443
+ /**
444
+ * Optional version of SafeUrlSchema that allows empty string for retrocompatibility on tos_uri and logo_uri
445
+ */
446
+ const OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => void 0));
447
+ /**
448
+ * RFC 7591 OAuth 2.0 Dynamic Client Registration metadata
449
+ */
450
+ const OAuthClientMetadataSchema = object({
451
+ redirect_uris: array(SafeUrlSchema),
452
+ token_endpoint_auth_method: string().optional(),
453
+ grant_types: array(string()).optional(),
454
+ response_types: array(string()).optional(),
455
+ client_name: string().optional(),
456
+ client_uri: SafeUrlSchema.optional(),
457
+ logo_uri: OptionalSafeUrlSchema,
458
+ scope: string().optional(),
459
+ contacts: array(string()).optional(),
460
+ tos_uri: OptionalSafeUrlSchema,
461
+ policy_uri: string().optional(),
462
+ jwks_uri: SafeUrlSchema.optional(),
463
+ jwks: any().optional(),
464
+ software_id: string().optional(),
465
+ software_version: string().optional(),
466
+ software_statement: string().optional()
467
+ }).strip();
468
+ /**
469
+ * RFC 7591 OAuth 2.0 Dynamic Client Registration client information
470
+ */
471
+ const OAuthClientInformationSchema = object({
472
+ client_id: string(),
473
+ client_secret: string().optional(),
474
+ client_id_issued_at: number$1().optional(),
475
+ client_secret_expires_at: number$1().optional(),
476
+ /**
477
+ * Not part of the wire format: the authorization server this value was obtained from, added by
478
+ * the client's `auth()` before it is stored and compared when it is read back.
479
+ */
480
+ issuer: string().optional().catch(void 0)
481
+ }).strip();
482
+ /**
483
+ * RFC 7591 OAuth 2.0 Dynamic Client Registration full response (client information plus metadata)
484
+ */
485
+ const OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
486
+ object({
487
+ error: string(),
488
+ error_description: string().optional()
489
+ }).strip();
490
+ object({
491
+ token: string(),
492
+ token_type_hint: string().optional()
493
+ }).strip();
494
+ //#endregion
495
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
496
+ /**
497
+ * Utilities for handling OAuth resource URIs.
498
+ */
499
+ /**
500
+ * Converts a server URL to a resource URL by removing the fragment.
501
+ * RFC 8707 section 2 states that resource URIs "MUST NOT include a fragment component".
502
+ * Keeps everything else unchanged (scheme, domain, port, path, query).
503
+ */
504
+ function resourceUrlFromServerUrl(url) {
505
+ const resourceURL = typeof url === "string" ? new URL(url) : new URL(url.href);
506
+ resourceURL.hash = "";
507
+ return resourceURL;
508
+ }
509
+ /**
510
+ * Checks if a requested resource URL matches a configured resource URL.
511
+ * A requested resource matches if it has the same scheme, domain, port,
512
+ * and its path starts with the configured resource's path.
513
+ *
514
+ * @param requestedResource The resource URL being requested
515
+ * @param configuredResource The resource URL that has been configured
516
+ * @returns true if the requested resource matches the configured resource, false otherwise
517
+ */
518
+ function checkResourceAllowed({ requestedResource, configuredResource }) {
519
+ const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
520
+ const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
521
+ if (requested.origin !== configured.origin) return false;
522
+ if (requested.pathname.length < configured.pathname.length) return false;
523
+ const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
524
+ const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
525
+ return requestedPath.startsWith(configuredPath);
526
+ }
527
+ //#endregion
528
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
529
+ /**
530
+ * Base class for all OAuth errors
531
+ */
532
+ var OAuthError = class extends Error {
533
+ constructor(message, errorUri) {
534
+ super(message);
535
+ this.errorUri = errorUri;
536
+ this.name = this.constructor.name;
537
+ }
538
+ /**
539
+ * Converts the error to a standard OAuth error response object
540
+ */
541
+ toResponseObject() {
542
+ const response = {
543
+ error: this.errorCode,
544
+ error_description: this.message
545
+ };
546
+ if (this.errorUri) response.error_uri = this.errorUri;
547
+ return response;
548
+ }
549
+ get errorCode() {
550
+ return this.constructor.errorCode;
551
+ }
552
+ };
553
+ /**
554
+ * Invalid request error - The request is missing a required parameter,
555
+ * includes an invalid parameter value, includes a parameter more than once,
556
+ * or is otherwise malformed.
557
+ */
558
+ var InvalidRequestError = class extends OAuthError {};
559
+ InvalidRequestError.errorCode = "invalid_request";
560
+ /**
561
+ * Invalid client error - Client authentication failed (e.g., unknown client, no client
562
+ * authentication included, or unsupported authentication method).
563
+ */
564
+ var InvalidClientError = class extends OAuthError {};
565
+ InvalidClientError.errorCode = "invalid_client";
566
+ /**
567
+ * Invalid grant error - The provided authorization grant or refresh token is
568
+ * invalid, expired, revoked, does not match the redirection URI used in the
569
+ * authorization request, or was issued to another client.
570
+ */
571
+ var InvalidGrantError = class extends OAuthError {};
572
+ InvalidGrantError.errorCode = "invalid_grant";
573
+ /**
574
+ * Unauthorized client error - The authenticated client is not authorized to use
575
+ * this authorization grant type.
576
+ */
577
+ var UnauthorizedClientError = class extends OAuthError {};
578
+ UnauthorizedClientError.errorCode = "unauthorized_client";
579
+ /**
580
+ * Unsupported grant type error - The authorization grant type is not supported
581
+ * by the authorization server.
582
+ */
583
+ var UnsupportedGrantTypeError = class extends OAuthError {};
584
+ UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
585
+ /**
586
+ * Invalid scope error - The requested scope is invalid, unknown, malformed, or
587
+ * exceeds the scope granted by the resource owner.
588
+ */
589
+ var InvalidScopeError = class extends OAuthError {};
590
+ InvalidScopeError.errorCode = "invalid_scope";
591
+ /**
592
+ * Access denied error - The resource owner or authorization server denied the request.
593
+ */
594
+ var AccessDeniedError = class extends OAuthError {};
595
+ AccessDeniedError.errorCode = "access_denied";
596
+ /**
597
+ * Server error - The authorization server encountered an unexpected condition
598
+ * that prevented it from fulfilling the request.
599
+ */
600
+ var ServerError = class extends OAuthError {};
601
+ ServerError.errorCode = "server_error";
602
+ /**
603
+ * Temporarily unavailable error - The authorization server is currently unable to
604
+ * handle the request due to a temporary overloading or maintenance of the server.
605
+ */
606
+ var TemporarilyUnavailableError = class extends OAuthError {};
607
+ TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
608
+ /**
609
+ * Unsupported response type error - The authorization server does not support
610
+ * obtaining an authorization code using this method.
611
+ */
612
+ var UnsupportedResponseTypeError = class extends OAuthError {};
613
+ UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
614
+ /**
615
+ * Unsupported token type error - The authorization server does not support
616
+ * the requested token type.
617
+ */
618
+ var UnsupportedTokenTypeError = class extends OAuthError {};
619
+ UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
620
+ /**
621
+ * Invalid token error - The access token provided is expired, revoked, malformed,
622
+ * or invalid for other reasons.
623
+ */
624
+ var InvalidTokenError = class extends OAuthError {};
625
+ InvalidTokenError.errorCode = "invalid_token";
626
+ /**
627
+ * Method not allowed error - The HTTP method used is not allowed for this endpoint.
628
+ * (Custom, non-standard error)
629
+ */
630
+ var MethodNotAllowedError = class extends OAuthError {};
631
+ MethodNotAllowedError.errorCode = "method_not_allowed";
632
+ /**
633
+ * Too many requests error - Rate limit exceeded.
634
+ * (Custom, non-standard error based on RFC 6585)
635
+ */
636
+ var TooManyRequestsError = class extends OAuthError {};
637
+ TooManyRequestsError.errorCode = "too_many_requests";
638
+ /**
639
+ * Invalid client metadata error - The client metadata is invalid.
640
+ * (Custom error for dynamic client registration - RFC 7591)
641
+ */
642
+ var InvalidClientMetadataError = class extends OAuthError {};
643
+ InvalidClientMetadataError.errorCode = "invalid_client_metadata";
644
+ /**
645
+ * Insufficient scope error - The request requires higher privileges than provided by the access token.
646
+ */
647
+ var InsufficientScopeError = class extends OAuthError {};
648
+ InsufficientScopeError.errorCode = "insufficient_scope";
649
+ /**
650
+ * Invalid target error - The requested resource is invalid, missing, unknown, or malformed.
651
+ * (Custom error for resource indicators - RFC 8707)
652
+ */
653
+ var InvalidTargetError = class extends OAuthError {};
654
+ InvalidTargetError.errorCode = "invalid_target";
655
+ /**
656
+ * A full list of all OAuthErrors, enabling parsing from error responses
657
+ */
658
+ const OAUTH_ERRORS = {
659
+ [InvalidRequestError.errorCode]: InvalidRequestError,
660
+ [InvalidClientError.errorCode]: InvalidClientError,
661
+ [InvalidGrantError.errorCode]: InvalidGrantError,
662
+ [UnauthorizedClientError.errorCode]: UnauthorizedClientError,
663
+ [UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
664
+ [InvalidScopeError.errorCode]: InvalidScopeError,
665
+ [AccessDeniedError.errorCode]: AccessDeniedError,
666
+ [ServerError.errorCode]: ServerError,
667
+ [TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
668
+ [UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
669
+ [UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
670
+ [InvalidTokenError.errorCode]: InvalidTokenError,
671
+ [MethodNotAllowedError.errorCode]: MethodNotAllowedError,
672
+ [TooManyRequestsError.errorCode]: TooManyRequestsError,
673
+ [InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
674
+ [InsufficientScopeError.errorCode]: InsufficientScopeError,
675
+ [InvalidTargetError.errorCode]: InvalidTargetError
676
+ };
677
+ //#endregion
678
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
679
+ var UnauthorizedError = class extends Error {
680
+ constructor(message) {
681
+ super(message ?? "Unauthorized");
682
+ }
683
+ };
684
+ function isClientAuthMethod(method) {
685
+ return [
686
+ "client_secret_basic",
687
+ "client_secret_post",
688
+ "none"
689
+ ].includes(method);
690
+ }
691
+ const AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
692
+ const AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
693
+ /**
694
+ * Determines the best client authentication method to use based on server support and client configuration.
695
+ *
696
+ * Priority order (highest to lowest):
697
+ * 1. client_secret_basic (if client secret is available)
698
+ * 2. client_secret_post (if client secret is available)
699
+ * 3. none (for public clients)
700
+ *
701
+ * @param clientInformation - OAuth client information containing credentials
702
+ * @param supportedMethods - Authentication methods supported by the authorization server
703
+ * @returns The selected authentication method
704
+ */
705
+ function selectClientAuthMethod(clientInformation, supportedMethods) {
706
+ const hasClientSecret = clientInformation.client_secret !== void 0;
707
+ if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) return clientInformation.token_endpoint_auth_method;
708
+ if (supportedMethods.length === 0) return hasClientSecret ? "client_secret_basic" : "none";
709
+ if (hasClientSecret && supportedMethods.includes("client_secret_basic")) return "client_secret_basic";
710
+ if (hasClientSecret && supportedMethods.includes("client_secret_post")) return "client_secret_post";
711
+ if (supportedMethods.includes("none")) return "none";
712
+ return hasClientSecret ? "client_secret_post" : "none";
713
+ }
714
+ /**
715
+ * Applies client authentication to the request based on the specified method.
716
+ *
717
+ * Implements OAuth 2.1 client authentication methods:
718
+ * - client_secret_basic: HTTP Basic authentication (RFC 6749 Section 2.3.1)
719
+ * - client_secret_post: Credentials in request body (RFC 6749 Section 2.3.1)
720
+ * - none: Public client authentication (RFC 6749 Section 2.1)
721
+ *
722
+ * @param method - The authentication method to use
723
+ * @param clientInformation - OAuth client information containing credentials
724
+ * @param headers - HTTP headers object to modify
725
+ * @param params - URL search parameters to modify
726
+ * @throws {Error} When required credentials are missing
727
+ */
728
+ function applyClientAuthentication(method, clientInformation, headers, params) {
729
+ const { client_id, client_secret } = clientInformation;
730
+ switch (method) {
731
+ case "client_secret_basic":
732
+ applyBasicAuth(client_id, client_secret, headers);
733
+ return;
734
+ case "client_secret_post":
735
+ applyPostAuth(client_id, client_secret, params);
736
+ return;
737
+ case "none":
738
+ applyPublicAuth(client_id, params);
739
+ return;
740
+ default: throw new Error(`Unsupported client authentication method: ${method}`);
741
+ }
742
+ }
743
+ /**
744
+ * Applies HTTP Basic authentication (RFC 6749 Section 2.3.1)
745
+ */
746
+ function applyBasicAuth(clientId, clientSecret, headers) {
747
+ if (!clientSecret) throw new Error("client_secret_basic authentication requires a client_secret");
748
+ const credentials = btoa(`${clientId}:${clientSecret}`);
749
+ headers.set("Authorization", `Basic ${credentials}`);
750
+ }
751
+ /**
752
+ * Applies POST body authentication (RFC 6749 Section 2.3.1)
753
+ */
754
+ function applyPostAuth(clientId, clientSecret, params) {
755
+ params.set("client_id", clientId);
756
+ if (clientSecret) params.set("client_secret", clientSecret);
757
+ }
758
+ /**
759
+ * Applies public client authentication (RFC 6749 Section 2.1)
760
+ */
761
+ function applyPublicAuth(clientId, params) {
762
+ params.set("client_id", clientId);
763
+ }
764
+ /**
765
+ * Parses an OAuth error response from a string or Response object.
766
+ *
767
+ * If the input is a standard OAuth2.0 error response, it will be parsed according to the spec
768
+ * and an instance of the appropriate OAuthError subclass will be returned.
769
+ * If parsing fails, it falls back to a generic ServerError that includes
770
+ * the response status (if available) and original content.
771
+ *
772
+ * @param input - A Response object or string containing the error response
773
+ * @returns A Promise that resolves to an OAuthError instance
774
+ */
775
+ async function parseErrorResponse(input) {
776
+ const statusCode = input instanceof Response ? input.status : void 0;
777
+ const body = input instanceof Response ? await input.text() : input;
778
+ try {
779
+ const { error, error_description, error_uri } = OAuthErrorResponseSchema.parse(JSON.parse(body));
780
+ return new (OAUTH_ERRORS[error] || ServerError)(error_description || "", error_uri);
781
+ } catch (error) {
782
+ const redirect = input instanceof Response ? unfollowedRedirect(input, input.url) : void 0;
783
+ return new ServerError(`${statusCode ? `HTTP ${statusCode}: ` : ""}${redirect ?? `Invalid OAuth error response: ${error}. Raw body: ${body}`}`);
784
+ }
785
+ }
786
+ /**
787
+ * Compares two authorization server identifiers, tolerating a single trailing `/`
788
+ * difference (`String(new URL(...))` is slash-suffixed, advertised values often are not).
789
+ */
790
+ function issuersMatch(a, b) {
791
+ let [x, y] = [a, b];
792
+ try {
793
+ [x, y] = [new URL(a).href, new URL(b).href];
794
+ } catch {}
795
+ return x === y || x.endsWith("/") && x.slice(0, -1) === y || y.endsWith("/") && y.slice(0, -1) === x;
796
+ }
797
+ /**
798
+ * {@linkcode auth} stamps everything it passes to `saveClientInformation` / `saveTokens` with
799
+ * `issuer`, the authorization server URL used for discovery. This returns `stored` unless its
800
+ * stamp names a different authorization server, in which case the caller behaves as if nothing
801
+ * were stored. A value without a stamp (saved by an earlier version) is returned as-is, and
802
+ * is stamped once this authorization server has accepted it.
803
+ */
804
+ function discardIfIssuerMismatch(stored, issuer) {
805
+ if (!stored) return void 0;
806
+ if (typeof stored.issuer !== "string") return stored.issuer == null ? stored : {
807
+ ...stored,
808
+ issuer: void 0
809
+ };
810
+ return issuersMatch(stored.issuer, issuer) ? stored : void 0;
811
+ }
812
+ const TokenResponseSchema = OAuthTokensSchema.omit({ issuer: true });
813
+ const RegistrationResponseSchema = OAuthClientInformationFullSchema.omit({ issuer: true });
814
+ function boundElsewhereError(stored, issuer) {
815
+ return /* @__PURE__ */ new Error(`OAuth client information is bound to authorization server ${stored.issuer} and is not presented to ${issuer}. Clear the stored client information, or correct \`expectedIssuer\`, if the authorization server has moved.`);
816
+ }
817
+ /**
818
+ * Orchestrates the full auth flow with a server.
819
+ *
820
+ * This can be used as a single entry point for all authorization functionality,
821
+ * instead of linking together the other lower-level functions in this module.
822
+ */
823
+ async function auth(provider, options) {
824
+ try {
825
+ return await authInternal(provider, options);
826
+ } catch (error) {
827
+ if (error instanceof InvalidClientError || error instanceof UnauthorizedClientError) {
828
+ await provider.invalidateCredentials?.("all");
829
+ return await authInternal(provider, options);
830
+ } else if (error instanceof InvalidGrantError) {
831
+ await provider.invalidateCredentials?.("tokens");
832
+ return await authInternal(provider, options);
833
+ }
834
+ throw error;
835
+ }
836
+ }
837
+ async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
838
+ const cachedState = await provider.discoveryState?.();
839
+ let resourceMetadata;
840
+ let authorizationServerUrl;
841
+ let metadata;
842
+ let effectiveResourceMetadataUrl = resourceMetadataUrl;
843
+ if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
844
+ if (cachedState?.authorizationServerUrl) {
845
+ authorizationServerUrl = cachedState.authorizationServerUrl;
846
+ resourceMetadata = cachedState.resourceMetadata;
847
+ metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
848
+ if (!resourceMetadata) try {
849
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
850
+ } catch {}
851
+ if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) await provider.saveDiscoveryState?.({
852
+ authorizationServerUrl: String(authorizationServerUrl),
853
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
854
+ resourceMetadata,
855
+ authorizationServerMetadata: metadata
856
+ });
857
+ } else {
858
+ const serverInfo = await discoverOAuthServerInfo(serverUrl, {
859
+ resourceMetadataUrl: effectiveResourceMetadataUrl,
860
+ fetchFn
861
+ });
862
+ authorizationServerUrl = serverInfo.authorizationServerUrl;
863
+ metadata = serverInfo.authorizationServerMetadata;
864
+ resourceMetadata = serverInfo.resourceMetadata;
865
+ await provider.saveDiscoveryState?.({
866
+ authorizationServerUrl: String(authorizationServerUrl),
867
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
868
+ resourceMetadata,
869
+ authorizationServerMetadata: metadata
870
+ });
871
+ }
872
+ const issuer = String(authorizationServerUrl);
873
+ const selectedResource = await selectResourceURL(serverUrl, provider, resourceMetadata);
874
+ const resource = selectedResource && resourceMetadata && !provider.validateResourceURL ? resourceMetadata.resource : selectedResource;
875
+ const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
876
+ const storedClientInformation = await Promise.resolve(provider.clientInformation());
877
+ let clientInformation = discardIfIssuerMismatch(storedClientInformation, issuer);
878
+ const canRegisterAgain = provider.saveClientInformation !== void 0 && !!provider.redirectUrl;
879
+ if (storedClientInformation && !clientInformation && !canRegisterAgain) throw boundElsewhereError(storedClientInformation, issuer);
880
+ const unstampedClientInformation = clientInformation?.issuer == null ? clientInformation : void 0;
881
+ const bindClientInformation = async () => {
882
+ try {
883
+ if (unstampedClientInformation) await provider.saveClientInformation?.({
884
+ ...unstampedClientInformation,
885
+ issuer
886
+ });
887
+ } catch {}
888
+ };
889
+ if (!clientInformation) {
890
+ if (authorizationCode !== void 0) throw new Error("Existing OAuth client information is required when exchanging an authorization code");
891
+ const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
892
+ const clientMetadataUrl = provider.clientMetadataUrl;
893
+ if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
894
+ if (supportsUrlBasedClientId && clientMetadataUrl) {
895
+ clientInformation = {
896
+ client_id: clientMetadataUrl,
897
+ issuer
898
+ };
899
+ await provider.saveClientInformation?.(clientInformation);
900
+ } else {
901
+ if (!provider.saveClientInformation) throw new Error("OAuth client information must be saveable for dynamic registration");
902
+ clientInformation = {
903
+ ...await registerClient(authorizationServerUrl, {
904
+ metadata,
905
+ clientMetadata: provider.clientMetadata,
906
+ scope: resolvedScope,
907
+ fetchFn
908
+ }),
909
+ issuer
910
+ };
911
+ await provider.saveClientInformation(clientInformation);
912
+ }
913
+ }
914
+ const nonInteractiveFlow = !provider.redirectUrl;
915
+ if (authorizationCode !== void 0 || nonInteractiveFlow) {
916
+ const tokens = await fetchToken(provider, authorizationServerUrl, {
917
+ metadata,
918
+ resource,
919
+ authorizationCode,
920
+ fetchFn
921
+ });
922
+ await bindClientInformation();
923
+ await provider.saveTokens({
924
+ ...tokens,
925
+ issuer
926
+ });
927
+ return "AUTHORIZED";
928
+ }
929
+ const tokens = discardIfIssuerMismatch(await provider.tokens(), issuer);
930
+ if (tokens?.refresh_token && tokens.issuer == null) console.warn("[mcp-sdk] stored OAuth tokens have no 'issuer' property (saved by an earlier version, or by a provider that does not keep it) and are used as-is; make sure your OAuthClientProvider stores what saveTokens() and saveClientInformation() receive unchanged.");
931
+ if (tokens?.refresh_token) try {
932
+ const newTokens = await refreshAuthorization(authorizationServerUrl, {
933
+ metadata,
934
+ clientInformation,
935
+ refreshToken: tokens.refresh_token,
936
+ resource,
937
+ addClientAuthentication: provider.addClientAuthentication,
938
+ fetchFn
939
+ });
940
+ await bindClientInformation();
941
+ await provider.saveTokens({
942
+ ...newTokens,
943
+ issuer
944
+ });
945
+ return "AUTHORIZED";
946
+ } catch (error) {
947
+ if (!(error instanceof OAuthError) || error instanceof ServerError) {} else throw error;
948
+ }
949
+ const state = provider.state ? await provider.state() : void 0;
950
+ const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
951
+ metadata,
952
+ clientInformation,
953
+ state,
954
+ redirectUrl: provider.redirectUrl,
955
+ scope: resolvedScope,
956
+ resource
957
+ });
958
+ await provider.saveCodeVerifier(codeVerifier);
959
+ await provider.redirectToAuthorization(authorizationUrl);
960
+ return "REDIRECT";
961
+ }
962
+ /**
963
+ * SEP-991: URL-based Client IDs
964
+ * Validate that the client_id is a valid URL with https scheme
965
+ */
966
+ function isHttpsUrl(value) {
967
+ if (!value) return false;
968
+ try {
969
+ const url = new URL(value);
970
+ return url.protocol === "https:" && url.pathname !== "/";
971
+ } catch {
972
+ return false;
973
+ }
974
+ }
975
+ /**
976
+ * Selects the RFC 8707 resource indicator for an MCP server: the provider's
977
+ * {@linkcode OAuthClientProvider.validateResourceURL | validateResourceURL} result when
978
+ * implemented, otherwise the protected resource metadata's `resource` (checked against the
979
+ * server URL with `checkResourceAllowed`), or `undefined` when there is no metadata.
980
+ *
981
+ * The result is a parsed `URL`, so a pathless indicator such as `https://example.com` has
982
+ * the `href` `https://example.com/`. {@linkcode auth} therefore sends the metadata string
983
+ * verbatim instead of this URL's `href` (#1968); callers that emit the `resource`
984
+ * parameter themselves should do the same.
985
+ */
986
+ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
987
+ const defaultResource = resourceUrlFromServerUrl(serverUrl);
988
+ if (provider.validateResourceURL) return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
989
+ if (!resourceMetadata) return;
990
+ if (!checkResourceAllowed({
991
+ requestedResource: defaultResource,
992
+ configuredResource: resourceMetadata.resource
993
+ })) throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
994
+ return new URL(resourceMetadata.resource);
995
+ }
996
+ /**
997
+ * Extract resource_metadata, scope, and error from WWW-Authenticate header.
998
+ */
999
+ function extractWWWAuthenticateParams(res) {
1000
+ const authenticateHeader = res.headers.get("WWW-Authenticate");
1001
+ if (!authenticateHeader) return {};
1002
+ const [type, scheme] = authenticateHeader.split(" ");
1003
+ if (type.toLowerCase() !== "bearer" || !scheme) return {};
1004
+ const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0;
1005
+ let resourceMetadataUrl;
1006
+ if (resourceMetadataMatch) try {
1007
+ resourceMetadataUrl = new URL(resourceMetadataMatch);
1008
+ } catch {}
1009
+ const scope = extractFieldFromWwwAuth(res, "scope") || void 0;
1010
+ const error = extractFieldFromWwwAuth(res, "error") || void 0;
1011
+ return {
1012
+ resourceMetadataUrl,
1013
+ scope,
1014
+ error
1015
+ };
1016
+ }
1017
+ /**
1018
+ * Extracts a specific field's value from the WWW-Authenticate header string.
1019
+ *
1020
+ * @param response The HTTP response object containing the headers.
1021
+ * @param fieldName The name of the field to extract (e.g., "realm", "nonce").
1022
+ * @returns The field value
1023
+ */
1024
+ function extractFieldFromWwwAuth(response, fieldName) {
1025
+ const wwwAuthHeader = response.headers.get("WWW-Authenticate");
1026
+ if (!wwwAuthHeader) return null;
1027
+ const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
1028
+ const match = wwwAuthHeader.match(pattern);
1029
+ if (match) return match[1] || match[2];
1030
+ return null;
1031
+ }
1032
+ /**
1033
+ * Looks up RFC 9728 OAuth 2.0 Protected Resource Metadata.
1034
+ *
1035
+ * If the server returns a 404 for the well-known endpoint, this function will
1036
+ * return `undefined`. Any other errors will be thrown as exceptions.
1037
+ */
1038
+ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
1039
+ const response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
1040
+ protocolVersion: opts?.protocolVersion,
1041
+ metadataUrl: opts?.resourceMetadataUrl
1042
+ });
1043
+ if (!response || response.status === 404) {
1044
+ await response?.body?.cancel();
1045
+ throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
1046
+ }
1047
+ if (!response.ok) {
1048
+ await response.body?.cancel();
1049
+ throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
1050
+ }
1051
+ return OAuthProtectedResourceMetadataSchema.parse(await response.json());
1052
+ }
1053
+ /**
1054
+ * Helper function to handle fetch with CORS retry logic
1055
+ */
1056
+ async function fetchWithCorsRetry(url, headers, fetchFn = fetch) {
1057
+ try {
1058
+ return await fetchWithinOrigin(fetchFn)(url, { headers });
1059
+ } catch (error) {
1060
+ if (error instanceof TypeError) {
1061
+ if (headers) return fetchWithCorsRetry(url, void 0, fetchFn);
1062
+ else return;
1063
+ }
1064
+ throw error;
1065
+ }
1066
+ }
1067
+ /**
1068
+ * Constructs the well-known path for auth-related metadata discovery
1069
+ */
1070
+ function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
1071
+ if (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
1072
+ return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
1073
+ }
1074
+ /**
1075
+ * Tries to discover OAuth metadata at a specific URL
1076
+ */
1077
+ async function tryMetadataDiscovery(url, protocolVersion, fetchFn = fetch) {
1078
+ return await fetchWithCorsRetry(url, { "MCP-Protocol-Version": protocolVersion }, fetchFn);
1079
+ }
1080
+ /**
1081
+ * Determines if fallback to root discovery should be attempted
1082
+ */
1083
+ function shouldAttemptFallback(response, pathname) {
1084
+ return !response || !response.ok && response.status < 500 && pathname !== "/";
1085
+ }
1086
+ /**
1087
+ * Generic function for discovering OAuth metadata with fallback support
1088
+ */
1089
+ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
1090
+ const issuer = new URL(serverUrl);
1091
+ const protocolVersion = opts?.protocolVersion ?? "2025-11-25";
1092
+ let url;
1093
+ if (opts?.metadataUrl) url = new URL(opts.metadataUrl);
1094
+ else {
1095
+ const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
1096
+ url = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
1097
+ url.search = issuer.search;
1098
+ }
1099
+ let response = await tryMetadataDiscovery(url, protocolVersion, fetchFn);
1100
+ if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) response = await tryMetadataDiscovery(new URL(`/.well-known/${wellKnownType}`, issuer), protocolVersion, fetchFn);
1101
+ return response;
1102
+ }
1103
+ /**
1104
+ * Builds a list of discovery URLs to try for authorization server metadata.
1105
+ * URLs are returned in priority order:
1106
+ * 1. OAuth metadata at the given URL
1107
+ * 2. OIDC metadata endpoints at the given URL
1108
+ */
1109
+ function buildDiscoveryUrls(authorizationServerUrl) {
1110
+ const url = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
1111
+ const hasPath = url.pathname !== "/";
1112
+ const urlsToTry = [];
1113
+ if (!hasPath) {
1114
+ urlsToTry.push({
1115
+ url: new URL("/.well-known/oauth-authorization-server", url.origin),
1116
+ type: "oauth"
1117
+ });
1118
+ urlsToTry.push({
1119
+ url: new URL(`/.well-known/openid-configuration`, url.origin),
1120
+ type: "oidc"
1121
+ });
1122
+ return urlsToTry;
1123
+ }
1124
+ let pathname = url.pathname;
1125
+ if (pathname.endsWith("/")) pathname = pathname.slice(0, -1);
1126
+ urlsToTry.push({
1127
+ url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url.origin),
1128
+ type: "oauth"
1129
+ });
1130
+ urlsToTry.push({
1131
+ url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
1132
+ type: "oidc"
1133
+ });
1134
+ urlsToTry.push({
1135
+ url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
1136
+ type: "oidc"
1137
+ });
1138
+ return urlsToTry;
1139
+ }
1140
+ /**
1141
+ * Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
1142
+ * and OpenID Connect Discovery 1.0 specifications.
1143
+ *
1144
+ * This function implements a fallback strategy for authorization server discovery:
1145
+ * 1. Attempts RFC 8414 OAuth metadata discovery first
1146
+ * 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
1147
+ *
1148
+ * @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
1149
+ * protected resource metadata, or the MCP server's URL if the
1150
+ * metadata was not found.
1151
+ * @param options - Configuration options
1152
+ * @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
1153
+ * @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
1154
+ * @returns Promise resolving to authorization server metadata, or undefined if discovery fails
1155
+ */
1156
+ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
1157
+ const headers = {
1158
+ "MCP-Protocol-Version": protocolVersion,
1159
+ Accept: "application/json"
1160
+ };
1161
+ const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
1162
+ for (const { url: endpointUrl, type } of urlsToTry) {
1163
+ const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
1164
+ if (!response)
1165
+ /**
1166
+ * CORS error occurred - don't throw as the endpoint may not allow CORS,
1167
+ * continue trying other possible endpoints
1168
+ */
1169
+ continue;
1170
+ if (!response.ok) {
1171
+ await response.body?.cancel();
1172
+ if (response.status < 500) continue;
1173
+ throw new Error(`HTTP ${response.status} trying to load ${type === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
1174
+ }
1175
+ if (type === "oauth") return OAuthMetadataSchema.parse(await response.json());
1176
+ else return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
1177
+ }
1178
+ }
1179
+ /**
1180
+ * Discovers the authorization server for an MCP server following
1181
+ * {@link https://datatracker.ietf.org/doc/html/rfc9728 | RFC 9728} (OAuth 2.0 Protected
1182
+ * Resource Metadata), with fallback to treating the server URL as the
1183
+ * authorization server.
1184
+ *
1185
+ * This function combines two discovery steps into one call:
1186
+ * 1. Probes `/.well-known/oauth-protected-resource` on the MCP server to find the
1187
+ * authorization server URL (RFC 9728).
1188
+ * 2. Fetches authorization server metadata from that URL (RFC 8414 / OpenID Connect Discovery).
1189
+ *
1190
+ * Use this when you need the authorization server metadata for operations outside the
1191
+ * {@linkcode auth} orchestrator, such as token refresh or token revocation.
1192
+ *
1193
+ * @param serverUrl - The MCP resource server URL
1194
+ * @param opts - Optional configuration
1195
+ * @param opts.resourceMetadataUrl - Override URL for the protected resource metadata endpoint
1196
+ * @param opts.fetchFn - Custom fetch function for HTTP requests
1197
+ * @returns Authorization server URL, metadata, and resource metadata (if available)
1198
+ */
1199
+ async function discoverOAuthServerInfo(serverUrl, opts) {
1200
+ let resourceMetadata;
1201
+ let authorizationServerUrl;
1202
+ try {
1203
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
1204
+ if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) authorizationServerUrl = resourceMetadata.authorization_servers[0];
1205
+ } catch {}
1206
+ if (!authorizationServerUrl) authorizationServerUrl = String(new URL("/", serverUrl));
1207
+ const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
1208
+ return {
1209
+ authorizationServerUrl,
1210
+ authorizationServerMetadata,
1211
+ resourceMetadata
1212
+ };
1213
+ }
1214
+ function resourceIndicatorToString(resource) {
1215
+ return typeof resource === "string" ? resource : resource.href;
1216
+ }
1217
+ /**
1218
+ * Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
1219
+ */
1220
+ async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
1221
+ let authorizationUrl;
1222
+ if (metadata) {
1223
+ authorizationUrl = new URL(metadata.authorization_endpoint);
1224
+ if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
1225
+ if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
1226
+ } else authorizationUrl = new URL("/authorize", authorizationServerUrl);
1227
+ const challenge = await pkceChallenge();
1228
+ const codeVerifier = challenge.code_verifier;
1229
+ const codeChallenge = challenge.code_challenge;
1230
+ authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
1231
+ authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
1232
+ authorizationUrl.searchParams.set("code_challenge", codeChallenge);
1233
+ authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
1234
+ authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
1235
+ if (state) authorizationUrl.searchParams.set("state", state);
1236
+ if (scope) authorizationUrl.searchParams.set("scope", scope);
1237
+ if (scope?.includes("offline_access")) authorizationUrl.searchParams.append("prompt", "consent");
1238
+ if (resource) authorizationUrl.searchParams.set("resource", resourceIndicatorToString(resource));
1239
+ return {
1240
+ authorizationUrl,
1241
+ codeVerifier
1242
+ };
1243
+ }
1244
+ /**
1245
+ * Prepares token request parameters for an authorization code exchange.
1246
+ *
1247
+ * This is the default implementation used by fetchToken when the provider
1248
+ * doesn't implement prepareTokenRequest.
1249
+ *
1250
+ * @param authorizationCode - The authorization code received from the authorization endpoint
1251
+ * @param codeVerifier - The PKCE code verifier
1252
+ * @param redirectUri - The redirect URI used in the authorization request
1253
+ * @returns URLSearchParams for the authorization_code grant
1254
+ */
1255
+ function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
1256
+ return new URLSearchParams({
1257
+ grant_type: "authorization_code",
1258
+ code: authorizationCode,
1259
+ code_verifier: codeVerifier,
1260
+ redirect_uri: String(redirectUri)
1261
+ });
1262
+ }
1263
+ /**
1264
+ * Internal helper to execute a token request with the given parameters.
1265
+ * Used by exchangeAuthorization, refreshAuthorization, and fetchToken.
1266
+ */
1267
+ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
1268
+ const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
1269
+ const headers = new Headers({
1270
+ "Content-Type": "application/x-www-form-urlencoded",
1271
+ Accept: "application/json"
1272
+ });
1273
+ if (resource) tokenRequestParams.set("resource", resourceIndicatorToString(resource));
1274
+ if (addClientAuthentication) await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
1275
+ else if (clientInformation) applyClientAuthentication(selectClientAuthMethod(clientInformation, metadata?.token_endpoint_auth_methods_supported ?? []), clientInformation, headers, tokenRequestParams);
1276
+ const response = await fetchWithinOrigin(fetchFn ?? fetch)(tokenUrl, {
1277
+ method: "POST",
1278
+ headers,
1279
+ body: tokenRequestParams
1280
+ });
1281
+ if (!response.ok) throw await parseErrorResponse(response);
1282
+ return TokenResponseSchema.parse(await response.json());
1283
+ }
1284
+ /**
1285
+ * Exchange a refresh token for an updated access token.
1286
+ *
1287
+ * Supports multiple client authentication methods as specified in OAuth 2.1:
1288
+ * - Automatically selects the best authentication method based on server support
1289
+ * - Preserves the original refresh token if a new one is not returned
1290
+ *
1291
+ * @param authorizationServerUrl - The authorization server's base URL
1292
+ * @param options - Configuration object containing client info, refresh token, etc.
1293
+ * @returns Promise resolving to OAuth tokens (preserves original refresh_token if not replaced)
1294
+ * @throws {Error} When token refresh fails or authentication is invalid
1295
+ */
1296
+ async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
1297
+ return {
1298
+ refresh_token: refreshToken,
1299
+ ...await executeTokenRequest(authorizationServerUrl, {
1300
+ metadata,
1301
+ tokenRequestParams: new URLSearchParams({
1302
+ grant_type: "refresh_token",
1303
+ refresh_token: refreshToken
1304
+ }),
1305
+ clientInformation,
1306
+ addClientAuthentication,
1307
+ resource,
1308
+ fetchFn
1309
+ })
1310
+ };
1311
+ }
1312
+ /**
1313
+ * Unified token fetching that works with any grant type via provider.prepareTokenRequest().
1314
+ *
1315
+ * This function provides a single entry point for obtaining tokens regardless of the
1316
+ * OAuth grant type. The provider's prepareTokenRequest() method determines which grant
1317
+ * to use and supplies the grant-specific parameters.
1318
+ *
1319
+ * @param provider - OAuth client provider that implements prepareTokenRequest()
1320
+ * @param authorizationServerUrl - The authorization server's base URL
1321
+ * @param options - Configuration for the token request
1322
+ * @returns Promise resolving to OAuth tokens
1323
+ * @throws {Error} When provider doesn't implement prepareTokenRequest or token fetch fails
1324
+ *
1325
+ * @example
1326
+ * // Provider for client_credentials:
1327
+ * class MyProvider implements OAuthClientProvider {
1328
+ * prepareTokenRequest(scope) {
1329
+ * const params = new URLSearchParams({ grant_type: 'client_credentials' });
1330
+ * if (scope) params.set('scope', scope);
1331
+ * return params;
1332
+ * }
1333
+ * // ... other methods
1334
+ * }
1335
+ *
1336
+ * const tokens = await fetchToken(provider, authServerUrl, { metadata });
1337
+ */
1338
+ async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
1339
+ const readClientInformation = async () => {
1340
+ const storedClientInformation = await provider.clientInformation();
1341
+ const checked = discardIfIssuerMismatch(storedClientInformation, String(authorizationServerUrl));
1342
+ if (storedClientInformation && !checked) throw boundElsewhereError(storedClientInformation, String(authorizationServerUrl));
1343
+ return checked;
1344
+ };
1345
+ let clientInformation = await readClientInformation();
1346
+ const scope = provider.clientMetadata.scope;
1347
+ let tokenRequestParams;
1348
+ if (provider.prepareTokenRequest) tokenRequestParams = await provider.prepareTokenRequest(scope);
1349
+ if (!tokenRequestParams) {
1350
+ if (!authorizationCode) throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
1351
+ if (!provider.redirectUrl) throw new Error("redirectUrl is required for authorization_code flow");
1352
+ tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, await provider.codeVerifier(), provider.redirectUrl);
1353
+ }
1354
+ clientInformation ?? (clientInformation = await readClientInformation());
1355
+ return executeTokenRequest(authorizationServerUrl, {
1356
+ metadata,
1357
+ tokenRequestParams,
1358
+ clientInformation,
1359
+ addClientAuthentication: provider.addClientAuthentication,
1360
+ resource,
1361
+ fetchFn
1362
+ });
1363
+ }
1364
+ /**
1365
+ * Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
1366
+ *
1367
+ * If `scope` is provided, it overrides `clientMetadata.scope` in the registration
1368
+ * request body. This allows callers to apply the Scope Selection Strategy (SEP-835)
1369
+ * consistently across both DCR and the subsequent authorization request.
1370
+ */
1371
+ async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
1372
+ let registrationUrl;
1373
+ if (metadata) {
1374
+ if (!metadata.registration_endpoint) throw new Error("Incompatible auth server: does not support dynamic client registration");
1375
+ registrationUrl = new URL(metadata.registration_endpoint);
1376
+ } else registrationUrl = new URL("/register", authorizationServerUrl);
1377
+ const response = await fetchWithinOrigin(fetchFn ?? fetch)(registrationUrl, {
1378
+ method: "POST",
1379
+ headers: { "Content-Type": "application/json" },
1380
+ body: JSON.stringify({
1381
+ ...clientMetadata,
1382
+ ...scope !== void 0 ? { scope } : {}
1383
+ })
1384
+ });
1385
+ if (!response.ok) throw await parseErrorResponse(response);
1386
+ return RegistrationResponseSchema.parse(await response.json());
1387
+ }
1388
+ //#endregion
1389
+ //#region ../../node_modules/.pnpm/eventsource-parser@3.1.1/node_modules/eventsource-parser/dist/index.js
1390
+ var ParseError = class extends Error {
1391
+ constructor(message, options) {
1392
+ super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
1393
+ }
1394
+ };
1395
+ const LF = 10;
1396
+ const CR = 13;
1397
+ const SPACE = 32;
1398
+ function noop(_arg) {}
1399
+ function createParser(config) {
1400
+ if (typeof config == "function") throw new TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");
1401
+ const { onEvent = noop, onError = noop, onRetry = noop, onComment, maxBufferSize } = config, pendingFragments = [];
1402
+ let pendingFragmentsLength = 0, isFirstChunk = !0, id, data = "", dataLines = 0, eventType, terminated = !1;
1403
+ function feed(chunk) {
1404
+ if (terminated) throw new Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");
1405
+ if (isFirstChunk && (isFirstChunk = !1, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
1406
+ const trailing2 = processLines(chunk);
1407
+ trailing2 !== "" && (pendingFragments.push(trailing2), pendingFragmentsLength = trailing2.length), checkBufferSize();
1408
+ return;
1409
+ }
1410
+ if (chunk.indexOf(`
1411
+ `) === -1 && chunk.indexOf("\r") === -1) {
1412
+ pendingFragments.push(chunk), pendingFragmentsLength += chunk.length, checkBufferSize();
1413
+ return;
1414
+ }
1415
+ pendingFragments.push(chunk);
1416
+ const input = pendingFragments.join("");
1417
+ pendingFragments.length = 0, pendingFragmentsLength = 0;
1418
+ const trailing = processLines(input);
1419
+ trailing !== "" && (pendingFragments.push(trailing), pendingFragmentsLength = trailing.length), checkBufferSize();
1420
+ }
1421
+ function checkBufferSize() {
1422
+ maxBufferSize !== void 0 && (pendingFragmentsLength + data.length <= maxBufferSize || (terminated = !0, pendingFragments.length = 0, pendingFragmentsLength = 0, id = void 0, data = "", dataLines = 0, eventType = void 0, onError(new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, { type: "max-buffer-size-exceeded" }))));
1423
+ }
1424
+ function processLines(chunk) {
1425
+ let searchIndex = 0;
1426
+ if (chunk.indexOf("\r") === -1) {
1427
+ let lfIndex = chunk.indexOf(`
1428
+ `, searchIndex);
1429
+ for (; lfIndex !== -1;) {
1430
+ if (searchIndex === lfIndex) {
1431
+ dataLines > 0 && onEvent({
1432
+ id,
1433
+ event: eventType,
1434
+ data
1435
+ }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
1436
+ `, searchIndex);
1437
+ continue;
1438
+ }
1439
+ const firstCharCode = chunk.charCodeAt(searchIndex);
1440
+ if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
1441
+ const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
1442
+ if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
1443
+ onEvent({
1444
+ id,
1445
+ event: eventType,
1446
+ data: value
1447
+ }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
1448
+ `, searchIndex);
1449
+ continue;
1450
+ }
1451
+ data = dataLines === 0 ? value : `${data}
1452
+ ${value}`, dataLines++;
1453
+ } else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6, lfIndex) || void 0 : parseLine(chunk, searchIndex, lfIndex);
1454
+ searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
1455
+ `, searchIndex);
1456
+ }
1457
+ return chunk.slice(searchIndex);
1458
+ }
1459
+ for (; searchIndex < chunk.length;) {
1460
+ const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
1461
+ `, searchIndex);
1462
+ let lineEnd = -1;
1463
+ if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) break;
1464
+ parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
1465
+ }
1466
+ return chunk.slice(searchIndex);
1467
+ }
1468
+ function parseLine(chunk, start, end) {
1469
+ if (start === end) {
1470
+ dispatchEvent();
1471
+ return;
1472
+ }
1473
+ const firstCharCode = chunk.charCodeAt(start);
1474
+ if (isDataPrefix(chunk, start, firstCharCode)) {
1475
+ const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
1476
+ data = dataLines === 0 ? value2 : `${data}
1477
+ ${value2}`, dataLines++;
1478
+ return;
1479
+ }
1480
+ if (isEventPrefix(chunk, start, firstCharCode)) {
1481
+ eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
1482
+ return;
1483
+ }
1484
+ if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
1485
+ const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
1486
+ value2.includes("\0") || (id = value2);
1487
+ return;
1488
+ }
1489
+ if (firstCharCode === 58) {
1490
+ if (onComment) {
1491
+ const line2 = chunk.slice(start, end);
1492
+ onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
1493
+ }
1494
+ return;
1495
+ }
1496
+ const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
1497
+ if (fieldSeparatorIndex === -1) {
1498
+ processField(line, "", line);
1499
+ return;
1500
+ }
1501
+ const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1;
1502
+ processField(field, line.slice(fieldSeparatorIndex + offset), line);
1503
+ }
1504
+ function processField(field, value, line) {
1505
+ switch (field) {
1506
+ case "event":
1507
+ eventType = value || void 0;
1508
+ break;
1509
+ case "data":
1510
+ data = dataLines === 0 ? value : `${data}
1511
+ ${value}`, dataLines++;
1512
+ break;
1513
+ case "id":
1514
+ value.includes("\0") || (id = value);
1515
+ break;
1516
+ case "retry":
1517
+ /^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(new ParseError(`Invalid \`retry\` value: "${value}"`, {
1518
+ type: "invalid-retry",
1519
+ value,
1520
+ line
1521
+ }));
1522
+ break;
1523
+ default: onError(new ParseError(`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`, {
1524
+ type: "unknown-field",
1525
+ field,
1526
+ value,
1527
+ line
1528
+ }));
1529
+ }
1530
+ }
1531
+ function dispatchEvent() {
1532
+ dataLines > 0 && onEvent({
1533
+ id,
1534
+ event: eventType,
1535
+ data
1536
+ }), id = void 0, data = "", dataLines = 0, eventType = void 0;
1537
+ }
1538
+ function reset(options = {}) {
1539
+ if (options.consume && pendingFragments.length > 0) {
1540
+ const incompleteLine = pendingFragments.join("");
1541
+ parseLine(incompleteLine, 0, incompleteLine.length);
1542
+ }
1543
+ isFirstChunk = !0, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0, pendingFragmentsLength = 0, terminated = !1;
1544
+ }
1545
+ return {
1546
+ feed,
1547
+ reset
1548
+ };
1549
+ }
1550
+ function isDataPrefix(chunk, i, firstCharCode) {
1551
+ return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
1552
+ }
1553
+ function isEventPrefix(chunk, i, firstCharCode) {
1554
+ return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
1555
+ }
1556
+ //#endregion
1557
+ //#region ../../node_modules/.pnpm/eventsource-parser@3.1.1/node_modules/eventsource-parser/dist/stream.js
1558
+ var EventSourceParserStream = class extends TransformStream {
1559
+ constructor({ onError, onRetry, onComment, maxBufferSize } = {}) {
1560
+ let parser;
1561
+ super({
1562
+ start(controller) {
1563
+ parser = createParser({
1564
+ onEvent: (event) => {
1565
+ controller.enqueue(event);
1566
+ },
1567
+ onError(error) {
1568
+ typeof onError == "function" && onError(error), (onError === "terminate" || error.type === "max-buffer-size-exceeded") && controller.error(error);
1569
+ },
1570
+ onRetry,
1571
+ onComment,
1572
+ maxBufferSize
1573
+ });
1574
+ },
1575
+ transform(chunk) {
1576
+ parser.feed(chunk);
1577
+ }
1578
+ });
1579
+ }
1580
+ };
1581
+ //#endregion
1582
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.6.7/node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
1583
+ const DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
1584
+ initialReconnectionDelay: 1e3,
1585
+ maxReconnectionDelay: 3e4,
1586
+ reconnectionDelayGrowFactor: 1.5,
1587
+ maxRetries: 2
1588
+ };
1589
+ var StreamableHTTPError = class extends Error {
1590
+ constructor(code, message) {
1591
+ super(`Streamable HTTP error: ${message}`);
1592
+ this.code = code;
1593
+ }
1594
+ };
1595
+ /**
1596
+ * Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
1597
+ * It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events
1598
+ * for receiving messages.
1599
+ */
1600
+ var StreamableHTTPClientTransport = class {
1601
+ constructor(url, opts) {
1602
+ this._hasCompletedAuthFlow = false;
1603
+ this._url = url;
1604
+ this._resourceMetadataUrl = void 0;
1605
+ this._scope = void 0;
1606
+ this._requestInit = opts?.requestInit;
1607
+ this._authProvider = opts?.authProvider;
1608
+ this._fetch = opts?.fetch;
1609
+ this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
1610
+ this._followRedirects = opts?.redirectPolicy === "follow";
1611
+ if (this._followRedirects) {
1612
+ this._fetch = fetchLeavingRedirects(this._fetch);
1613
+ this._fetchWithInit = fetchLeavingRedirects(this._fetchWithInit);
1614
+ }
1615
+ this._sessionId = opts?.sessionId;
1616
+ this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
1617
+ }
1618
+ /** Error text for a redirect `response` that was not followed, or `undefined` for any other response. */
1619
+ _unfollowedRedirect(response, url) {
1620
+ const text = unfollowedRedirect(response, url);
1621
+ return text && !this._followRedirects ? `${text} (redirectPolicy: 'same-origin')` : text;
1622
+ }
1623
+ async _authThenStart() {
1624
+ if (!this._authProvider) throw new UnauthorizedError("No auth provider");
1625
+ let result;
1626
+ try {
1627
+ result = await auth(this._authProvider, {
1628
+ serverUrl: this._url,
1629
+ resourceMetadataUrl: this._resourceMetadataUrl,
1630
+ scope: this._scope,
1631
+ fetchFn: this._fetchWithInit
1632
+ });
1633
+ } catch (error) {
1634
+ this.onerror?.(error);
1635
+ throw error;
1636
+ }
1637
+ if (result !== "AUTHORIZED") throw new UnauthorizedError();
1638
+ return await this._startOrAuthSse({ resumptionToken: void 0 });
1639
+ }
1640
+ async _commonHeaders() {
1641
+ const headers = {};
1642
+ if (this._authProvider) {
1643
+ const tokens = await this._authProvider.tokens();
1644
+ if (tokens) headers["Authorization"] = `Bearer ${tokens.access_token}`;
1645
+ }
1646
+ if (this._sessionId) headers["mcp-session-id"] = this._sessionId;
1647
+ if (this._protocolVersion) headers["mcp-protocol-version"] = this._protocolVersion;
1648
+ const extraHeaders = normalizeHeaders(this._requestInit?.headers);
1649
+ return new Headers({
1650
+ ...headers,
1651
+ ...extraHeaders
1652
+ });
1653
+ }
1654
+ async _startOrAuthSse(options) {
1655
+ const { resumptionToken } = options;
1656
+ try {
1657
+ const headers = await this._commonHeaders();
1658
+ headers.set("Accept", "text/event-stream");
1659
+ if (resumptionToken) headers.set("last-event-id", resumptionToken);
1660
+ const fetchFn = this._fetch ?? fetch;
1661
+ const init = {
1662
+ method: "GET",
1663
+ headers,
1664
+ signal: this._abortController?.signal
1665
+ };
1666
+ let response = await fetchFn(this._url, this._followRedirects ? init : {
1667
+ ...init,
1668
+ redirect: "manual"
1669
+ });
1670
+ const followed = this._followRedirects ? void 0 : followWithinOrigin(fetchFn, this._url, init, response);
1671
+ if (followed) response = await followed;
1672
+ if (!response.ok) {
1673
+ await response.body?.cancel();
1674
+ if (response.status === 401 && this._authProvider) return await this._authThenStart();
1675
+ if (response.status === 405) return;
1676
+ throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${this._unfollowedRedirect(response, this._url) ?? response.statusText}`);
1677
+ }
1678
+ this._handleSseStream(response.body, options, true);
1679
+ } catch (error) {
1680
+ this.onerror?.(error);
1681
+ throw error;
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Calculates the next reconnection delay using backoff algorithm
1686
+ *
1687
+ * @param attempt Current reconnection attempt count for the specific stream
1688
+ * @returns Time to wait in milliseconds before next reconnection attempt
1689
+ */
1690
+ _getNextReconnectionDelay(attempt) {
1691
+ if (this._serverRetryMs !== void 0) return this._serverRetryMs;
1692
+ const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
1693
+ const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
1694
+ const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
1695
+ return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
1696
+ }
1697
+ /**
1698
+ * Schedule a reconnection attempt using server-provided retry interval or backoff
1699
+ *
1700
+ * @param lastEventId The ID of the last received event for resumability
1701
+ * @param attemptCount Current reconnection attempt count for this specific stream
1702
+ */
1703
+ _scheduleReconnection(options, attemptCount = 0) {
1704
+ const maxRetries = this._reconnectionOptions.maxRetries;
1705
+ if (attemptCount >= maxRetries) {
1706
+ this.onerror?.(/* @__PURE__ */ new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
1707
+ return;
1708
+ }
1709
+ const delay = this._getNextReconnectionDelay(attemptCount);
1710
+ this._reconnectionTimeout = setTimeout(() => {
1711
+ this._startOrAuthSse(options).catch((error) => {
1712
+ this.onerror?.(/* @__PURE__ */ new Error(`Failed to reconnect SSE stream: ${error instanceof Error ? error.message : String(error)}`));
1713
+ this._scheduleReconnection(options, attemptCount + 1);
1714
+ });
1715
+ }, delay);
1716
+ }
1717
+ _handleSseStream(stream, options, isReconnectable) {
1718
+ if (!stream) return;
1719
+ const { onresumptiontoken, replayMessageId } = options;
1720
+ let lastEventId;
1721
+ let hasPrimingEvent = false;
1722
+ let receivedResponse = false;
1723
+ const processStream = async () => {
1724
+ try {
1725
+ const reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({ onRetry: (retryMs) => {
1726
+ this._serverRetryMs = retryMs;
1727
+ } })).getReader();
1728
+ while (true) {
1729
+ const { value: event, done } = await reader.read();
1730
+ if (done) break;
1731
+ if (event.id) {
1732
+ lastEventId = event.id;
1733
+ hasPrimingEvent = true;
1734
+ onresumptiontoken?.(event.id);
1735
+ }
1736
+ if (!event.data) continue;
1737
+ if (!event.event || event.event === "message") try {
1738
+ const message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
1739
+ if (isJSONRPCResultResponse(message)) {
1740
+ receivedResponse = true;
1741
+ if (replayMessageId !== void 0) message.id = replayMessageId;
1742
+ }
1743
+ this.onmessage?.(message);
1744
+ } catch (error) {
1745
+ this.onerror?.(error);
1746
+ }
1747
+ }
1748
+ if ((isReconnectable || hasPrimingEvent) && !receivedResponse && this._abortController && !this._abortController.signal.aborted) this._scheduleReconnection({
1749
+ resumptionToken: lastEventId,
1750
+ onresumptiontoken,
1751
+ replayMessageId
1752
+ }, 0);
1753
+ } catch (error) {
1754
+ this.onerror?.(/* @__PURE__ */ new Error(`SSE stream disconnected: ${error}`));
1755
+ if ((isReconnectable || hasPrimingEvent) && !receivedResponse && this._abortController && !this._abortController.signal.aborted) try {
1756
+ this._scheduleReconnection({
1757
+ resumptionToken: lastEventId,
1758
+ onresumptiontoken,
1759
+ replayMessageId
1760
+ }, 0);
1761
+ } catch (error) {
1762
+ this.onerror?.(/* @__PURE__ */ new Error(`Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`));
1763
+ }
1764
+ }
1765
+ };
1766
+ processStream();
1767
+ }
1768
+ async start() {
1769
+ if (this._abortController) throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
1770
+ this._abortController = new AbortController();
1771
+ }
1772
+ /**
1773
+ * Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
1774
+ */
1775
+ async finishAuth(authorizationCode) {
1776
+ if (!this._authProvider) throw new UnauthorizedError("No auth provider");
1777
+ if (await auth(this._authProvider, {
1778
+ serverUrl: this._url,
1779
+ authorizationCode,
1780
+ resourceMetadataUrl: this._resourceMetadataUrl,
1781
+ scope: this._scope,
1782
+ fetchFn: this._fetchWithInit
1783
+ }) !== "AUTHORIZED") throw new UnauthorizedError("Failed to authorize");
1784
+ }
1785
+ async close() {
1786
+ if (this._reconnectionTimeout) {
1787
+ clearTimeout(this._reconnectionTimeout);
1788
+ this._reconnectionTimeout = void 0;
1789
+ }
1790
+ this._abortController?.abort();
1791
+ this.onclose?.();
1792
+ }
1793
+ async send(message, options) {
1794
+ try {
1795
+ const { resumptionToken, onresumptiontoken } = options || {};
1796
+ if (resumptionToken) {
1797
+ this._startOrAuthSse({
1798
+ resumptionToken,
1799
+ replayMessageId: isJSONRPCRequest(message) ? message.id : void 0
1800
+ }).catch((err) => this.onerror?.(err));
1801
+ return;
1802
+ }
1803
+ const headers = await this._commonHeaders();
1804
+ headers.set("content-type", "application/json");
1805
+ headers.set("accept", "application/json, text/event-stream");
1806
+ const init = {
1807
+ ...this._requestInit,
1808
+ method: "POST",
1809
+ headers,
1810
+ body: JSON.stringify(message),
1811
+ signal: this._abortController?.signal
1812
+ };
1813
+ const response = await fetchWithinOrigin(this._fetch ?? fetch)(this._url, init);
1814
+ const sessionId = response.headers.get("mcp-session-id");
1815
+ if (sessionId) this._sessionId = sessionId;
1816
+ if (!response.ok) {
1817
+ const text = await response.text().catch(() => null);
1818
+ if (response.status === 401 && this._authProvider) {
1819
+ if (this._hasCompletedAuthFlow) throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
1820
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
1821
+ this._resourceMetadataUrl = resourceMetadataUrl;
1822
+ this._scope = scope;
1823
+ if (await auth(this._authProvider, {
1824
+ serverUrl: this._url,
1825
+ resourceMetadataUrl: this._resourceMetadataUrl,
1826
+ scope: this._scope,
1827
+ fetchFn: this._fetchWithInit
1828
+ }) !== "AUTHORIZED") throw new UnauthorizedError();
1829
+ this._hasCompletedAuthFlow = true;
1830
+ return this.send(message);
1831
+ }
1832
+ if (response.status === 403 && this._authProvider) {
1833
+ const { resourceMetadataUrl, scope, error } = extractWWWAuthenticateParams(response);
1834
+ if (error === "insufficient_scope") {
1835
+ const wwwAuthHeader = response.headers.get("WWW-Authenticate");
1836
+ if (this._lastUpscopingHeader === wwwAuthHeader) throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
1837
+ if (scope) this._scope = scope;
1838
+ if (resourceMetadataUrl) this._resourceMetadataUrl = resourceMetadataUrl;
1839
+ this._lastUpscopingHeader = wwwAuthHeader ?? void 0;
1840
+ if (await auth(this._authProvider, {
1841
+ serverUrl: this._url,
1842
+ resourceMetadataUrl: this._resourceMetadataUrl,
1843
+ scope: this._scope,
1844
+ fetchFn: this._fetch
1845
+ }) !== "AUTHORIZED") throw new UnauthorizedError();
1846
+ return this.send(message);
1847
+ }
1848
+ }
1849
+ throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${this._unfollowedRedirect(response, this._url) ?? text}`);
1850
+ }
1851
+ this._hasCompletedAuthFlow = false;
1852
+ this._lastUpscopingHeader = void 0;
1853
+ if (response.status === 202) {
1854
+ await response.body?.cancel();
1855
+ if (isInitializedNotification(message)) this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
1856
+ return;
1857
+ }
1858
+ const hasRequests = (Array.isArray(message) ? message : [message]).filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0;
1859
+ const contentType = response.headers.get("content-type");
1860
+ const responseMediaType = mediaTypeEssence(contentType);
1861
+ if (hasRequests) {
1862
+ if (responseMediaType === "text/event-stream") this._handleSseStream(response.body, { onresumptiontoken }, false);
1863
+ else if (responseMediaType === "application/json") {
1864
+ const data = await response.json();
1865
+ const responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
1866
+ for (const msg of responseMessages) this.onmessage?.(msg);
1867
+ } else {
1868
+ await response.body?.cancel();
1869
+ throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
1870
+ }
1871
+ } else await response.body?.cancel();
1872
+ } catch (error) {
1873
+ this.onerror?.(error);
1874
+ throw error;
1875
+ }
1876
+ }
1877
+ get sessionId() {
1878
+ return this._sessionId;
1879
+ }
1880
+ /**
1881
+ * Terminates the current session by sending a DELETE request to the server.
1882
+ *
1883
+ * Clients that no longer need a particular session
1884
+ * (e.g., because the user is leaving the client application) SHOULD send an
1885
+ * HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
1886
+ * terminate the session.
1887
+ *
1888
+ * The server MAY respond with HTTP 405 Method Not Allowed, indicating that
1889
+ * the server does not allow clients to terminate sessions.
1890
+ */
1891
+ async terminateSession() {
1892
+ if (!this._sessionId) return;
1893
+ try {
1894
+ const headers = await this._commonHeaders();
1895
+ const init = {
1896
+ ...this._requestInit,
1897
+ method: "DELETE",
1898
+ headers,
1899
+ signal: this._abortController?.signal
1900
+ };
1901
+ const response = await fetchWithinOrigin(this._fetch ?? fetch)(this._url, init);
1902
+ await response.body?.cancel();
1903
+ if (!response.ok && response.status !== 405) throw new StreamableHTTPError(response.status, `Failed to terminate session: ${this._unfollowedRedirect(response, this._url) ?? response.statusText}`);
1904
+ this._sessionId = void 0;
1905
+ } catch (error) {
1906
+ this.onerror?.(error);
1907
+ throw error;
1908
+ }
1909
+ }
1910
+ setProtocolVersion(version) {
1911
+ this._protocolVersion = version;
1912
+ }
1913
+ get protocolVersion() {
1914
+ return this._protocolVersion;
1915
+ }
1916
+ /**
1917
+ * Resume an SSE stream from a previous event ID.
1918
+ * Opens a GET SSE connection with Last-Event-ID header to replay missed events.
1919
+ *
1920
+ * @param lastEventId The event ID to resume from
1921
+ * @param options Optional callback to receive new resumption tokens
1922
+ */
1923
+ async resumeStream(lastEventId, options) {
1924
+ await this._startOrAuthSse({
1925
+ resumptionToken: lastEventId,
1926
+ onresumptiontoken: options?.onresumptiontoken
1927
+ });
1928
+ }
1929
+ };
1930
+ //#endregion
1931
+ export { StreamableHTTPError as n, StreamableHTTPClientTransport as t };