poe-code 3.0.420 → 3.0.421

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 (27) hide show
  1. package/dist/index.js +3 -1
  2. package/dist/index.js.map +2 -2
  3. package/dist/metafile.json +1 -1
  4. package/package.json +3 -1
  5. package/packages/package-lint/dist/model.d.ts +2 -0
  6. package/packages/package-lint/dist/model.js +4 -0
  7. package/packages/package-lint/dist/rules/imported-workspace-dep-unresolvable.js +3 -0
  8. package/packages/tiny-mcp-client/dist/index.d.ts +660 -2
  9. package/packages/tiny-mcp-client/dist/index.js +3870 -1
  10. package/packages/tiny-mcp-client/dist/internal.d.ts +0 -556
  11. package/packages/tiny-mcp-client/dist/internal.js +0 -2688
  12. package/packages/tiny-mcp-client/dist/jsonrpc-types.compile-check.d.ts +0 -1
  13. package/packages/tiny-mcp-client/dist/jsonrpc-types.compile-check.js +0 -37
  14. package/packages/tiny-mcp-client/dist/mcp-lifecycle-types.compile-check.d.ts +0 -1
  15. package/packages/tiny-mcp-client/dist/mcp-lifecycle-types.compile-check.js +0 -50
  16. package/packages/tiny-mcp-client/dist/mcp-prompt-types.compile-check.d.ts +0 -1
  17. package/packages/tiny-mcp-client/dist/mcp-prompt-types.compile-check.js +0 -50
  18. package/packages/tiny-mcp-client/dist/mcp-resource-types.compile-check.d.ts +0 -1
  19. package/packages/tiny-mcp-client/dist/mcp-resource-types.compile-check.js +0 -51
  20. package/packages/tiny-mcp-client/dist/mcp-tool-types.compile-check.d.ts +0 -1
  21. package/packages/tiny-mcp-client/dist/mcp-tool-types.compile-check.js +0 -99
  22. package/packages/tiny-mcp-client/dist/mcp-transport-types.compile-check.d.ts +0 -1
  23. package/packages/tiny-mcp-client/dist/mcp-transport-types.compile-check.js +0 -56
  24. package/packages/tiny-mcp-client/dist/mcp-utility-types.compile-check.d.ts +0 -1
  25. package/packages/tiny-mcp-client/dist/mcp-utility-types.compile-check.js +0 -145
  26. package/packages/tiny-mcp-client/dist/oauth-discovery.d.ts +0 -24
  27. package/packages/tiny-mcp-client/dist/oauth-discovery.js +0 -382
@@ -1 +1,3870 @@
1
- export { createInMemoryTransportPair, discoverOAuthMetadata, createSdkTestPair, createTestPair, ERROR_INTERNAL, ERROR_INVALID_PARAMS, ERROR_INVALID_REQUEST, ERROR_METHOD_NOT_FOUND, ERROR_PARSE, HttpTransport, JsonRpcMessageLayer, McpClient, McpError, OAuthMetadataDiscovery, StdioTransport, } from "./internal.js";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res, err) => function __init() {
4
+ if (err) throw err[0];
5
+ try {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ } catch (e) {
8
+ throw err = [e], e;
9
+ }
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+
16
+ // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/inMemory.js
17
+ var inMemory_exports = {};
18
+ __export(inMemory_exports, {
19
+ InMemoryTransport: () => InMemoryTransport
20
+ });
21
+ var InMemoryTransport;
22
+ var init_inMemory = __esm({
23
+ "../../node_modules/@modelcontextprotocol/sdk/dist/esm/inMemory.js"() {
24
+ InMemoryTransport = class _InMemoryTransport {
25
+ constructor() {
26
+ this._messageQueue = [];
27
+ }
28
+ /**
29
+ * Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a Client and one to a Server.
30
+ */
31
+ static createLinkedPair() {
32
+ const clientTransport = new _InMemoryTransport();
33
+ const serverTransport = new _InMemoryTransport();
34
+ clientTransport._otherTransport = serverTransport;
35
+ serverTransport._otherTransport = clientTransport;
36
+ return [clientTransport, serverTransport];
37
+ }
38
+ async start() {
39
+ while (this._messageQueue.length > 0) {
40
+ const queuedMessage = this._messageQueue.shift();
41
+ this.onmessage?.(queuedMessage.message, queuedMessage.extra);
42
+ }
43
+ }
44
+ async close() {
45
+ const other = this._otherTransport;
46
+ this._otherTransport = void 0;
47
+ await other?.close();
48
+ this.onclose?.();
49
+ }
50
+ /**
51
+ * Sends a message with optional auth info.
52
+ * This is useful for testing authentication scenarios.
53
+ */
54
+ async send(message, options) {
55
+ if (!this._otherTransport) {
56
+ throw new Error("Not connected");
57
+ }
58
+ if (this._otherTransport.onmessage) {
59
+ this._otherTransport.onmessage(message, { authInfo: options?.authInfo });
60
+ } else {
61
+ this._otherTransport._messageQueue.push({ message, extra: { authInfo: options?.authInfo } });
62
+ }
63
+ }
64
+ };
65
+ }
66
+ });
67
+
68
+ // src/internal.ts
69
+ import { spawn as spawn2 } from "node:child_process";
70
+ import { PassThrough } from "node:stream";
71
+
72
+ // ../mcp-oauth/dist/client/auth-store-session-store.js
73
+ import crypto from "node:crypto";
74
+ import path2 from "node:path";
75
+
76
+ // ../auth-store/dist/encrypted-file-store.js
77
+ import { createCipheriv, createDecipheriv, randomBytes, randomUUID, scrypt } from "node:crypto";
78
+ import { promises as fs } from "node:fs";
79
+ import { homedir, hostname, userInfo } from "node:os";
80
+ import path from "node:path";
81
+
82
+ // ../auth-store/dist/error-codes.js
83
+ function hasOwnErrorCode(error, code) {
84
+ return error instanceof Error && Object.prototype.hasOwnProperty.call(error, "code") && error.code === code;
85
+ }
86
+
87
+ // ../auth-store/dist/encrypted-file-store.js
88
+ var derivedKeyCache = /* @__PURE__ */ new Map();
89
+ var ENCRYPTION_ALGORITHM = "aes-256-gcm";
90
+ var ENCRYPTION_VERSION = 1;
91
+ var ENCRYPTION_KEY_BYTES = 32;
92
+ var ENCRYPTION_IV_BYTES = 12;
93
+ var ENCRYPTION_AUTH_TAG_BYTES = 16;
94
+ var ENCRYPTION_FILE_MODE = 384;
95
+ var EncryptedFileStore = class {
96
+ fs;
97
+ filePath;
98
+ symbolicLinkCheckStartPath;
99
+ salt;
100
+ getMachineIdentity;
101
+ getRandomBytes;
102
+ keyPromise = null;
103
+ constructor(input) {
104
+ this.fs = input.fs ?? fs;
105
+ this.salt = input.salt;
106
+ if (input.filePath === void 0) {
107
+ const homeDirectory = (input.getHomeDirectory ?? homedir)();
108
+ const defaultDirectory = input.defaultDirectory ?? ".auth-store";
109
+ const defaultFileName = input.defaultFileName ?? "credentials.enc";
110
+ assertSafeDefaultDirectory(defaultDirectory);
111
+ assertSafeDefaultFileName(defaultFileName);
112
+ this.filePath = path.join(homeDirectory, defaultDirectory, defaultFileName);
113
+ this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory);
114
+ } else {
115
+ this.filePath = input.filePath;
116
+ this.symbolicLinkCheckStartPath = null;
117
+ }
118
+ this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
119
+ this.getRandomBytes = input.getRandomBytes ?? randomBytes;
120
+ }
121
+ async get() {
122
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
123
+ let rawDocument;
124
+ try {
125
+ rawDocument = await this.fs.readFile(this.filePath, "utf8");
126
+ } catch (error) {
127
+ if (isNotFoundError(error)) {
128
+ return null;
129
+ }
130
+ throw error;
131
+ }
132
+ const document = parseEncryptedDocument(rawDocument);
133
+ if (!document) {
134
+ return null;
135
+ }
136
+ const key2 = await this.getEncryptionKey();
137
+ try {
138
+ const iv = Buffer.from(document.iv, "base64");
139
+ const authTag = Buffer.from(document.authTag, "base64");
140
+ const ciphertext = Buffer.from(document.ciphertext, "base64");
141
+ if (iv.byteLength !== ENCRYPTION_IV_BYTES || authTag.byteLength !== ENCRYPTION_AUTH_TAG_BYTES) {
142
+ return null;
143
+ }
144
+ const decipher = createDecipheriv(ENCRYPTION_ALGORITHM, key2, iv);
145
+ decipher.setAuthTag(authTag);
146
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
147
+ return plaintext.toString("utf8");
148
+ } catch {
149
+ return null;
150
+ }
151
+ }
152
+ async set(value) {
153
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
154
+ const key2 = await this.getEncryptionKey();
155
+ const iv = this.getRandomBytes(ENCRYPTION_IV_BYTES);
156
+ const cipher = createCipheriv(ENCRYPTION_ALGORITHM, key2, iv);
157
+ const ciphertext = Buffer.concat([
158
+ cipher.update(value, "utf8"),
159
+ cipher.final()
160
+ ]);
161
+ const authTag = cipher.getAuthTag();
162
+ const document = {
163
+ version: ENCRYPTION_VERSION,
164
+ iv: iv.toString("base64"),
165
+ authTag: authTag.toString("base64"),
166
+ ciphertext: ciphertext.toString("base64")
167
+ };
168
+ await this.fs.mkdir(path.dirname(this.filePath), { recursive: true });
169
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
170
+ const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID()}.tmp`;
171
+ let temporaryCreated = false;
172
+ try {
173
+ await this.assertCredentialPathHasNoSymbolicLinks(temporaryPath);
174
+ await this.fs.writeFile(temporaryPath, JSON.stringify(document), {
175
+ encoding: "utf8",
176
+ flag: "wx",
177
+ mode: ENCRYPTION_FILE_MODE
178
+ });
179
+ temporaryCreated = true;
180
+ await this.fs.chmod(temporaryPath, ENCRYPTION_FILE_MODE);
181
+ await this.fs.rename(temporaryPath, this.filePath);
182
+ } catch (error) {
183
+ if (temporaryCreated || !isAlreadyExistsError(error)) {
184
+ await removeIfPresent(this.fs, temporaryPath).catch(() => void 0);
185
+ }
186
+ throw error;
187
+ }
188
+ }
189
+ async delete() {
190
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
191
+ try {
192
+ await this.fs.unlink(this.filePath);
193
+ } catch (error) {
194
+ if (!isNotFoundError(error)) {
195
+ throw error;
196
+ }
197
+ }
198
+ }
199
+ async assertCredentialPathHasNoSymbolicLinks(targetPath) {
200
+ const resolvedPath = path.resolve(targetPath);
201
+ const protectedPaths = getProtectedCredentialPaths(resolvedPath, this.symbolicLinkCheckStartPath);
202
+ for (const currentPath of protectedPaths) {
203
+ try {
204
+ const stats = await this.fs.lstat(currentPath);
205
+ if (stats.isSymbolicLink()) {
206
+ throw new Error(`Refusing to use encrypted credential path through symbolic link: ${currentPath}`);
207
+ }
208
+ } catch (error) {
209
+ if (isNotFoundError(error)) {
210
+ return;
211
+ }
212
+ throw error;
213
+ }
214
+ }
215
+ }
216
+ getEncryptionKey() {
217
+ if (!this.keyPromise) {
218
+ const retryableKeyPromise = deriveEncryptionKey(this.getMachineIdentity, this.salt).catch((error) => {
219
+ if (this.keyPromise === retryableKeyPromise) {
220
+ this.keyPromise = null;
221
+ }
222
+ throw error;
223
+ });
224
+ this.keyPromise = retryableKeyPromise;
225
+ }
226
+ return this.keyPromise;
227
+ }
228
+ };
229
+ function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
230
+ const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
231
+ return path.resolve(homeDirectory, firstSegment ?? ".");
232
+ }
233
+ function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
234
+ if (symbolicLinkCheckStartPath === null) {
235
+ return getExplicitProtectedCredentialPaths(resolvedPath);
236
+ }
237
+ const resolvedStartPath = path.resolve(symbolicLinkCheckStartPath);
238
+ if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
239
+ return [path.dirname(resolvedPath), resolvedPath];
240
+ }
241
+ const protectedPaths = [resolvedStartPath];
242
+ let currentPath = resolvedStartPath;
243
+ for (const segment of path.relative(resolvedStartPath, resolvedPath).split(path.sep).filter(Boolean)) {
244
+ currentPath = path.join(currentPath, segment);
245
+ protectedPaths.push(currentPath);
246
+ }
247
+ return protectedPaths;
248
+ }
249
+ function assertSafeDefaultDirectory(defaultDirectory) {
250
+ if (path.isAbsolute(defaultDirectory) || path.win32.isAbsolute(defaultDirectory)) {
251
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
252
+ }
253
+ for (const segment of splitPathSegments(defaultDirectory)) {
254
+ if (segment === "..") {
255
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
256
+ }
257
+ }
258
+ }
259
+ function assertSafeDefaultFileName(defaultFileName) {
260
+ if (defaultFileName.trim().length === 0 || defaultFileName === "." || defaultFileName === ".." || splitPathSegments(defaultFileName).length !== 1) {
261
+ throw new Error("defaultFileName must be a file name without path separators");
262
+ }
263
+ }
264
+ function splitPathSegments(value) {
265
+ return value.split("/").flatMap((segment) => segment.split("\\")).filter((segment) => segment.length > 0);
266
+ }
267
+ function getExplicitProtectedCredentialPaths(resolvedPath) {
268
+ const parsed = path.parse(resolvedPath);
269
+ const segments = resolvedPath.slice(parsed.root.length).split(path.sep).filter((segment) => segment.length > 0);
270
+ if (segments.length <= 1) {
271
+ return [resolvedPath];
272
+ }
273
+ const protectedPaths = [];
274
+ let currentPath = parsed.root;
275
+ for (const [index, segment] of segments.entries()) {
276
+ currentPath = path.join(currentPath, segment);
277
+ if (index === 0) {
278
+ continue;
279
+ }
280
+ protectedPaths.push(currentPath);
281
+ }
282
+ return protectedPaths;
283
+ }
284
+ function isPathInsideOrEqual(childPath, parentPath) {
285
+ const relativePath = path.relative(parentPath, childPath);
286
+ return relativePath === "" || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
287
+ }
288
+ async function removeIfPresent(fileSystem, filePath) {
289
+ try {
290
+ await fileSystem.unlink(filePath);
291
+ } catch (error) {
292
+ if (!isNotFoundError(error)) {
293
+ throw error;
294
+ }
295
+ }
296
+ }
297
+ function defaultMachineIdentity() {
298
+ return {
299
+ hostname: hostname(),
300
+ username: userInfo().username
301
+ };
302
+ }
303
+ async function deriveEncryptionKey(getMachineIdentity, salt) {
304
+ const machineIdentity = await getMachineIdentity();
305
+ const secret = `${machineIdentity.hostname}:${machineIdentity.username}`;
306
+ const cacheKey = JSON.stringify([machineIdentity.hostname, machineIdentity.username, salt]);
307
+ const cached = derivedKeyCache.get(cacheKey);
308
+ if (cached) {
309
+ return cached;
310
+ }
311
+ const keyPromise = new Promise((resolve, reject) => {
312
+ scrypt(secret, salt, ENCRYPTION_KEY_BYTES, (error, derivedKey) => {
313
+ if (error) {
314
+ reject(error);
315
+ return;
316
+ }
317
+ resolve(Buffer.from(derivedKey));
318
+ });
319
+ });
320
+ derivedKeyCache.set(cacheKey, keyPromise);
321
+ return keyPromise.catch((error) => {
322
+ if (derivedKeyCache.get(cacheKey) === keyPromise) {
323
+ derivedKeyCache.delete(cacheKey);
324
+ }
325
+ throw error;
326
+ });
327
+ }
328
+ function parseEncryptedDocument(raw) {
329
+ try {
330
+ const parsed = JSON.parse(raw);
331
+ if (!isRecord(parsed)) {
332
+ return null;
333
+ }
334
+ const version = getOwnEntry(parsed, "version");
335
+ const iv = getOwnEntry(parsed, "iv");
336
+ const authTag = getOwnEntry(parsed, "authTag");
337
+ const ciphertext = getOwnEntry(parsed, "ciphertext");
338
+ if (version !== ENCRYPTION_VERSION) {
339
+ return null;
340
+ }
341
+ if (typeof iv !== "string" || typeof authTag !== "string" || typeof ciphertext !== "string") {
342
+ return null;
343
+ }
344
+ return {
345
+ version,
346
+ iv,
347
+ authTag,
348
+ ciphertext
349
+ };
350
+ } catch {
351
+ return null;
352
+ }
353
+ }
354
+ function isRecord(value) {
355
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
356
+ }
357
+ function getOwnEntry(record, key2) {
358
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
359
+ }
360
+ function isNotFoundError(error) {
361
+ return hasOwnErrorCode(error, "ENOENT");
362
+ }
363
+ function isAlreadyExistsError(error) {
364
+ return hasOwnErrorCode(error, "EEXIST");
365
+ }
366
+
367
+ // ../auth-store/dist/keychain-store.js
368
+ import { spawn } from "node:child_process";
369
+ var SECURITY_CLI = "security";
370
+ var KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE = 44;
371
+ var KeychainStore = class {
372
+ runCommand;
373
+ service;
374
+ account;
375
+ constructor(input) {
376
+ this.runCommand = input.runCommand ?? runSecurityCommand;
377
+ this.service = input.service.trim();
378
+ this.account = input.account.trim();
379
+ if (this.service.length === 0) {
380
+ throw new Error("Keychain service must not be empty");
381
+ }
382
+ if (this.account.length === 0) {
383
+ throw new Error("Keychain account must not be empty");
384
+ }
385
+ }
386
+ async get() {
387
+ const result = await this.executeSecurityCommand(["find-generic-password", "-s", this.service, "-a", this.account, "-w"], "read secret from macOS Keychain");
388
+ if (getCommandExitCode(result) === 0) {
389
+ return stripTrailingLineBreak(getCommandOutput(result, "stdout"));
390
+ }
391
+ if (isKeychainEntryNotFound(result)) {
392
+ return null;
393
+ }
394
+ throw createSecurityCliFailure("read secret from macOS Keychain", result);
395
+ }
396
+ async set(value) {
397
+ if (value.includes("\n") || value.includes("\r")) {
398
+ throw new Error("Keychain secrets cannot contain line breaks");
399
+ }
400
+ const result = await this.executeSecurityCommand([
401
+ "add-generic-password",
402
+ "-s",
403
+ this.service,
404
+ "-a",
405
+ this.account,
406
+ "-U",
407
+ "-w",
408
+ value
409
+ ], "store secret in macOS Keychain");
410
+ if (getCommandExitCode(result) !== 0) {
411
+ throw createSecurityCliFailure("store secret in macOS Keychain", result);
412
+ }
413
+ }
414
+ async delete() {
415
+ const result = await this.executeSecurityCommand(["delete-generic-password", "-s", this.service, "-a", this.account], "delete secret from macOS Keychain");
416
+ if (getCommandExitCode(result) === 0 || isKeychainEntryNotFound(result)) {
417
+ return;
418
+ }
419
+ throw createSecurityCliFailure("delete secret from macOS Keychain", result);
420
+ }
421
+ async executeSecurityCommand(args, operation, options) {
422
+ try {
423
+ if (options === void 0) {
424
+ return await this.runCommand(SECURITY_CLI, args);
425
+ }
426
+ return await this.runCommand(SECURITY_CLI, args, options);
427
+ } catch (error) {
428
+ const message = error instanceof Error ? error.message : String(error);
429
+ throw new Error(`Failed to ${operation}: ${message}`);
430
+ }
431
+ }
432
+ };
433
+ function runSecurityCommand(command, args, options) {
434
+ return new Promise((resolve) => {
435
+ const child = spawn(command, args, {
436
+ stdio: [options?.stdin === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
437
+ });
438
+ let stdout = "";
439
+ let stderr = "";
440
+ let stdinErrorMessage;
441
+ const appendStderr = (message) => {
442
+ stderr = stderr.length === 0 ? message : `${stderr}${stderr.endsWith("\n") ? "" : "\n"}${message}`;
443
+ };
444
+ const appendStdinError = () => {
445
+ if (stdinErrorMessage === void 0) {
446
+ return;
447
+ }
448
+ appendStderr(stdinErrorMessage);
449
+ stdinErrorMessage = void 0;
450
+ };
451
+ child.stdout?.setEncoding("utf8");
452
+ child.stdout?.on("data", (chunk) => {
453
+ stdout += chunk.toString();
454
+ });
455
+ child.stderr?.setEncoding("utf8");
456
+ child.stderr?.on("data", (chunk) => {
457
+ stderr += chunk.toString();
458
+ });
459
+ if (options?.stdin !== void 0) {
460
+ child.stdin?.once("error", (error) => {
461
+ stdinErrorMessage = error instanceof Error ? error.message : String(error);
462
+ });
463
+ child.stdin?.end(options.stdin);
464
+ }
465
+ child.on("error", (error) => {
466
+ const message = error instanceof Error ? error.message : String(error ?? "Unknown error");
467
+ appendStdinError();
468
+ appendStderr(message);
469
+ resolve({
470
+ stdout,
471
+ stderr,
472
+ exitCode: 127
473
+ });
474
+ });
475
+ child.on("close", (code) => {
476
+ appendStdinError();
477
+ resolve({
478
+ stdout,
479
+ stderr,
480
+ exitCode: code ?? 1
481
+ });
482
+ });
483
+ });
484
+ }
485
+ function stripTrailingLineBreak(value) {
486
+ if (value.endsWith("\r\n")) {
487
+ return value.slice(0, -2);
488
+ }
489
+ if (value.endsWith("\n") || value.endsWith("\r")) {
490
+ return value.slice(0, -1);
491
+ }
492
+ return value;
493
+ }
494
+ function isKeychainEntryNotFound(result) {
495
+ return getCommandExitCode(result) === KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE;
496
+ }
497
+ function createSecurityCliFailure(operation, result) {
498
+ const exitCode = getCommandExitCode(result);
499
+ const details = getCommandOutput(result, "stderr").trim() || getCommandOutput(result, "stdout").trim();
500
+ if (details) {
501
+ return new Error(`Failed to ${operation}: security exited with code ${exitCode}: ${details}`);
502
+ }
503
+ return new Error(`Failed to ${operation}: security exited with code ${exitCode}`);
504
+ }
505
+ function getCommandExitCode(result) {
506
+ const value = getOwnEntry2(result, "exitCode");
507
+ return typeof value === "number" && Number.isInteger(value) ? value : 1;
508
+ }
509
+ function getCommandOutput(result, key2) {
510
+ const value = getOwnEntry2(result, key2);
511
+ return typeof value === "string" ? value : "";
512
+ }
513
+ function getOwnEntry2(record, key2) {
514
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
515
+ }
516
+
517
+ // ../auth-store/dist/create-secret-store.js
518
+ var DEFAULT_BACKEND_ENV_VAR = "AUTH_BACKEND";
519
+ var MACOS_PLATFORM = "darwin";
520
+ var storeFactories = {
521
+ file: (input) => {
522
+ if (!input.fileStore) {
523
+ throw new Error("fileStore configuration is required for file backend");
524
+ }
525
+ return new EncryptedFileStore(input.fileStore);
526
+ },
527
+ keychain: (input) => {
528
+ if (!input.keychainStore) {
529
+ throw new Error("keychainStore configuration is required for keychain backend");
530
+ }
531
+ return new KeychainStore(input.keychainStore);
532
+ }
533
+ };
534
+ function createSecretStore(input) {
535
+ const backend = resolveBackend(input);
536
+ const platform = input.platform ?? process.platform;
537
+ if (backend === "keychain" && platform !== MACOS_PLATFORM) {
538
+ throw new Error(`Keychain backend is only supported on macOS. Current platform: ${platform}`);
539
+ }
540
+ const store = storeFactories[backend](input);
541
+ return { backend, store };
542
+ }
543
+ function resolveBackend(input) {
544
+ const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
545
+ const configuredBackend = input.backend ?? getOwnEnvValue(input.env, envVar) ?? getOwnEnvValue(process.env, envVar);
546
+ const backend = configuredBackend?.trim();
547
+ if (backend === "keychain") {
548
+ return "keychain";
549
+ }
550
+ if (backend === void 0 || backend === "file") {
551
+ return "file";
552
+ }
553
+ throw new Error(`Unsupported auth store backend: ${backend}`);
554
+ }
555
+ function getOwnEnvValue(env, key2) {
556
+ return env !== void 0 && Object.prototype.hasOwnProperty.call(env, key2) ? env[key2] : void 0;
557
+ }
558
+
559
+ // ../mcp-oauth/dist/resource-indicator.js
560
+ function canonicalizeResourceIndicator(value) {
561
+ let url;
562
+ try {
563
+ url = value instanceof URL ? new URL(value.toString()) : new URL(value);
564
+ } catch {
565
+ throw new Error("Resource indicator must be an absolute URL");
566
+ }
567
+ url.hash = "";
568
+ return url.toString();
569
+ }
570
+
571
+ // ../mcp-oauth/dist/client/auth-store-session-store.js
572
+ var DEFAULT_FILE_SALT = "poe-code:mcp-oauth:v1";
573
+ var DEFAULT_FILE_DIRECTORY = ".poe-code/mcp-oauth";
574
+ var DEFAULT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth";
575
+ var DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
576
+ var DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
577
+ var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
578
+ var MAX_JS_DATE_MS = 864e13;
579
+ function createAuthStoreSessionStore(options = {}) {
580
+ return {
581
+ async load(resource) {
582
+ const store = createResourceSecretStore(resource, options);
583
+ const value = await store.get();
584
+ if (value === null) {
585
+ return null;
586
+ }
587
+ const parsed = JSON.parse(value);
588
+ if (isStoredOAuthSession(parsed)) {
589
+ return parsed;
590
+ }
591
+ throw new Error("Stored OAuth session must match the expected shape");
592
+ },
593
+ async save(resource, session) {
594
+ const store = createResourceSecretStore(resource, options);
595
+ await store.set(JSON.stringify(session));
596
+ },
597
+ async clear(resource) {
598
+ const store = createResourceSecretStore(resource, options);
599
+ await store.delete();
600
+ }
601
+ };
602
+ }
603
+ function createAuthStoreClientStore(options) {
604
+ return {
605
+ async load(issuer) {
606
+ const store = createIssuerSecretStore(issuer, options);
607
+ const value = await store.get();
608
+ if (value === null) {
609
+ return null;
610
+ }
611
+ const parsed = JSON.parse(value);
612
+ const clientId = isObjectRecord(parsed) ? getOwnString(parsed, "clientId") : void 0;
613
+ if (clientId !== void 0) {
614
+ const client = { clientId };
615
+ if (isObjectRecord(parsed) && Object.prototype.hasOwnProperty.call(parsed, "clientSecret")) {
616
+ client.clientSecret = getOwnEntry3(parsed, "clientSecret");
617
+ }
618
+ return client;
619
+ }
620
+ throw new Error("Stored OAuth client must be a JSON object with clientId");
621
+ },
622
+ async save(issuer, client) {
623
+ const store = createIssuerSecretStore(issuer, options);
624
+ await store.set(JSON.stringify(client));
625
+ },
626
+ async clear(issuer) {
627
+ const store = createIssuerSecretStore(issuer, options);
628
+ await store.delete();
629
+ }
630
+ };
631
+ }
632
+ function createNamedSecretStore(key2, options, defaults) {
633
+ const hash = crypto.createHash("sha256").update(key2).digest("hex");
634
+ const configuredFilePath = options.fileStore?.filePath;
635
+ const parsedFilePath = configuredFilePath === void 0 ? null : path2.parse(configuredFilePath);
636
+ const fileStore = {
637
+ ...options.fileStore,
638
+ filePath: parsedFilePath === null ? void 0 : path2.join(parsedFilePath.dir, `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`),
639
+ salt: options.fileStore?.salt ?? defaults.salt,
640
+ defaultDirectory: options.fileStore?.defaultDirectory || defaults.directory,
641
+ defaultFileName: parsedFilePath === null ? `${hash}.enc` : `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
642
+ };
643
+ const keychainStore = {
644
+ ...options.keychainStore,
645
+ service: options.keychainStore?.service ?? defaults.service,
646
+ account: `${options.keychainStore?.account ?? defaults.accountPrefix}:${hash}`
647
+ };
648
+ return createSecretStore({ ...options, fileStore, keychainStore }).store;
649
+ }
650
+ function createResourceSecretStore(resource, options) {
651
+ return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
652
+ salt: DEFAULT_FILE_SALT,
653
+ directory: DEFAULT_FILE_DIRECTORY,
654
+ service: DEFAULT_KEYCHAIN_SERVICE,
655
+ accountPrefix: "provider"
656
+ });
657
+ }
658
+ function createIssuerSecretStore(issuer, options) {
659
+ return createNamedSecretStore(issuer, options, {
660
+ salt: DEFAULT_CLIENT_FILE_SALT,
661
+ directory: DEFAULT_CLIENT_FILE_DIRECTORY,
662
+ service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
663
+ accountPrefix: "issuer"
664
+ });
665
+ }
666
+ function isObjectRecord(value) {
667
+ return typeof value === "object" && value !== null && !Array.isArray(value);
668
+ }
669
+ function getOwnEntry3(record, key2) {
670
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
671
+ }
672
+ function getOwnString(record, key2) {
673
+ const value = getOwnEntry3(record, key2);
674
+ return typeof value === "string" ? value : void 0;
675
+ }
676
+ function isStoredOAuthSession(value) {
677
+ if (!isObjectRecord(value)) {
678
+ return false;
679
+ }
680
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry3(value, "client")) && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
681
+ }
682
+ function isStoredOAuthClient(value) {
683
+ if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
684
+ return false;
685
+ }
686
+ const clientSecret = getOwnEntry3(value, "clientSecret");
687
+ return clientSecret === void 0 || typeof clientSecret === "string" && clientSecret.trim().length > 0;
688
+ }
689
+ function isStoredOAuthDiscovery(value) {
690
+ if (!isObjectRecord(value)) {
691
+ return false;
692
+ }
693
+ return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord(getOwnEntry3(value, "resourceMetadata")) && isObjectRecord(getOwnEntry3(value, "authorizationServerMetadata"));
694
+ }
695
+ function isStoredOAuthTokensOrMissing(value) {
696
+ if (value === void 0) {
697
+ return true;
698
+ }
699
+ if (!isObjectRecord(value)) {
700
+ return false;
701
+ }
702
+ if (!isNonBlankOwnString(value, "accessToken") || getOwnString(value, "tokenType") !== "Bearer") {
703
+ return false;
704
+ }
705
+ const expiresAt = getOwnEntry3(value, "expiresAt");
706
+ if (expiresAt !== null && (typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS || !Number.isFinite(new Date(expiresAt).getTime()))) {
707
+ return false;
708
+ }
709
+ const refreshToken = getOwnEntry3(value, "refreshToken");
710
+ if (refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
711
+ return false;
712
+ }
713
+ const scope = getOwnEntry3(value, "scope");
714
+ return scope === void 0 || typeof scope === "string" && scope.trim().length > 0;
715
+ }
716
+ function isNonBlankOwnString(record, key2) {
717
+ const value = getOwnString(record, key2);
718
+ return value !== void 0 && value.trim().length > 0;
719
+ }
720
+
721
+ // ../mcp-oauth/dist/client/default-oauth-client-provider.js
722
+ import { URL as URL2 } from "node:url";
723
+
724
+ // ../mcp-oauth/dist/client/loopback-authorization.js
725
+ import http from "node:http";
726
+
727
+ // ../mcp-oauth/dist/client/authorization-state.js
728
+ import crypto2 from "node:crypto";
729
+ function createAuthorizationState(input) {
730
+ const payload = {
731
+ v: 1,
732
+ n: crypto2.randomBytes(16).toString("base64url"),
733
+ i: input.issuer,
734
+ r: input.requireIssuer
735
+ };
736
+ return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
737
+ }
738
+ function parseAuthorizationState(value) {
739
+ if (value === null || value.length === 0) {
740
+ return null;
741
+ }
742
+ try {
743
+ const decoded = Buffer.from(value, "base64url").toString("utf8");
744
+ const parsed = JSON.parse(decoded);
745
+ if (!isObjectRecord2(parsed)) {
746
+ return null;
747
+ }
748
+ const version = getOwnEntry4(parsed, "v");
749
+ const nonce = getOwnEntry4(parsed, "n");
750
+ const issuer = getOwnEntry4(parsed, "i");
751
+ const requireIssuer = getOwnEntry4(parsed, "r");
752
+ if (version !== 1 || typeof nonce !== "string" || nonce.length === 0 || typeof issuer !== "string" || issuer.length === 0 || typeof requireIssuer !== "boolean") {
753
+ return null;
754
+ }
755
+ return {
756
+ issuer,
757
+ requireIssuer
758
+ };
759
+ } catch {
760
+ return null;
761
+ }
762
+ }
763
+ function isObjectRecord2(value) {
764
+ return typeof value === "object" && value !== null && !Array.isArray(value);
765
+ }
766
+ function getOwnEntry4(record, key2) {
767
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
768
+ }
769
+
770
+ // ../mcp-oauth/dist/client/loopback-authorization.js
771
+ async function createLoopbackAuthorizationSession(options = {}) {
772
+ const callbackPath = options.callbackPath ?? "/callback";
773
+ const server = options.createServer ? options.createServer() : http.createServer();
774
+ const port = await startServer(server);
775
+ const redirectUri = `http://127.0.0.1:${port}${callbackPath}`;
776
+ return {
777
+ redirectUri,
778
+ async waitForCode(authorizationUrl) {
779
+ return waitForAuthorizationCode(server, authorizationUrl, options, callbackPath);
780
+ },
781
+ close() {
782
+ server.closeAllConnections?.();
783
+ server.close();
784
+ }
785
+ };
786
+ }
787
+ async function startServer(server) {
788
+ return new Promise((resolve, reject) => {
789
+ const handleError = (error) => {
790
+ server.off("error", handleError);
791
+ reject(error);
792
+ };
793
+ server.once("error", handleError);
794
+ server.listen(0, "127.0.0.1", () => {
795
+ server.off("error", handleError);
796
+ const address = server.address();
797
+ resolve(address.port);
798
+ });
799
+ });
800
+ }
801
+ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPath) {
802
+ const expectedAuthorization = readExpectedAuthorizationCallback(authorizationUrl);
803
+ return new Promise((resolve, reject) => {
804
+ let settled = false;
805
+ const settle = (fn) => {
806
+ if (!settled) {
807
+ settled = true;
808
+ fn();
809
+ }
810
+ };
811
+ server.on("request", (req, res) => {
812
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
813
+ if (url.pathname !== callbackPath) {
814
+ res.writeHead(404);
815
+ res.end("Not found");
816
+ return;
817
+ }
818
+ const callbackParameters = {
819
+ code: url.searchParams.get("code"),
820
+ error: url.searchParams.get("error"),
821
+ errorDescription: url.searchParams.get("error_description"),
822
+ state: url.searchParams.get("state"),
823
+ iss: url.searchParams.get("iss")
824
+ };
825
+ try {
826
+ validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
827
+ } catch (error) {
828
+ res.writeHead(400);
829
+ res.end(error instanceof Error ? error.message : "Invalid OAuth callback");
830
+ settle(() => reject(error instanceof Error ? error : new Error(String(error))));
831
+ return;
832
+ }
833
+ const authorizationError = callbackParameters.error;
834
+ if (authorizationError !== null) {
835
+ const description = callbackParameters.errorDescription ?? authorizationError;
836
+ res.writeHead(400);
837
+ res.end(`Authorization failed: ${description}`);
838
+ settle(() => reject(createAuthorizationError(authorizationError, description)));
839
+ return;
840
+ }
841
+ try {
842
+ const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
843
+ res.writeHead(200, { "Content-Type": "text/html" });
844
+ res.end(buildSuccessPage(options.landingPage));
845
+ settle(() => resolve(code));
846
+ } catch (error) {
847
+ res.writeHead(400);
848
+ res.end(error instanceof Error ? error.message : "Invalid OAuth callback");
849
+ settle(() => reject(error instanceof Error ? error : new Error(String(error))));
850
+ }
851
+ });
852
+ if (options.readLine !== void 0) {
853
+ options.readLine().then((input) => {
854
+ const callbackParameters = extractCallbackParametersFromInput(input);
855
+ if (callbackParameters === null) {
856
+ settle(() => reject(new Error("OAuth callback missing authorization code")));
857
+ return;
858
+ }
859
+ try {
860
+ validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
861
+ if (callbackParameters.error !== null) {
862
+ const description = callbackParameters.errorDescription ?? callbackParameters.error;
863
+ throw createAuthorizationError(callbackParameters.error, description);
864
+ }
865
+ const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
866
+ settle(() => resolve(code));
867
+ } catch (error) {
868
+ settle(() => reject(error instanceof Error ? error : new Error(String(error))));
869
+ }
870
+ }).catch((error) => {
871
+ settle(() => reject(error instanceof Error ? error : new Error(String(error))));
872
+ });
873
+ }
874
+ if (options.openBrowser !== void 0) {
875
+ options.openBrowser(authorizationUrl).catch((error) => {
876
+ settle(() => reject(error));
877
+ });
878
+ }
879
+ });
880
+ }
881
+ function extractCallbackParametersFromInput(input) {
882
+ const trimmed = input.replaceAll("\r", "").replaceAll("\n", "").trim();
883
+ if (trimmed.length === 0) {
884
+ return null;
885
+ }
886
+ try {
887
+ const url = new URL(trimmed);
888
+ return {
889
+ code: url.searchParams.get("code"),
890
+ error: url.searchParams.get("error"),
891
+ errorDescription: url.searchParams.get("error_description"),
892
+ state: url.searchParams.get("state"),
893
+ iss: url.searchParams.get("iss")
894
+ };
895
+ } catch {
896
+ return {
897
+ code: trimmed,
898
+ error: null,
899
+ errorDescription: null,
900
+ state: null,
901
+ iss: null
902
+ };
903
+ }
904
+ }
905
+ function readExpectedAuthorizationCallback(authorizationUrl) {
906
+ const url = new URL(authorizationUrl);
907
+ const state = url.searchParams.get("state");
908
+ const parsedState = parseAuthorizationState(state);
909
+ return {
910
+ state,
911
+ issuer: parsedState?.issuer ?? null,
912
+ requireIssuer: parsedState?.requireIssuer ?? false
913
+ };
914
+ }
915
+ function validateAuthorizationCallbackParameters(callback, expected) {
916
+ validateAuthorizationCallbackBinding(callback, expected);
917
+ if (callback.code === null || callback.code.length === 0) {
918
+ throw new Error("OAuth callback missing authorization code");
919
+ }
920
+ return callback.code;
921
+ }
922
+ function validateAuthorizationCallbackBinding(callback, expected) {
923
+ if (expected.state !== null) {
924
+ if (callback.state === null || callback.state.length === 0) {
925
+ throw new Error("OAuth callback missing state");
926
+ }
927
+ if (callback.state !== expected.state) {
928
+ throw new Error("OAuth callback state mismatch");
929
+ }
930
+ }
931
+ if (expected.requireIssuer) {
932
+ if (callback.iss === null || callback.iss.length === 0) {
933
+ throw new Error("OAuth callback missing issuer");
934
+ }
935
+ }
936
+ if (callback.iss !== null && callback.iss.length > 0 && expected.issuer !== null && callback.iss !== expected.issuer) {
937
+ throw new Error("OAuth callback issuer mismatch");
938
+ }
939
+ }
940
+ function createAuthorizationError(error, description) {
941
+ return new Error(`OAuth authorization failed: ${error} \u2014 ${description}`);
942
+ }
943
+ function escapeHtml(text) {
944
+ return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
945
+ }
946
+ function buildSuccessPage(landingPage) {
947
+ const title = landingPage?.title ?? "Connected";
948
+ const body = landingPage?.body ?? "You can close this tab and return to your terminal.";
949
+ return [
950
+ "<!DOCTYPE html>",
951
+ `<html><head><meta charset=utf-8><title>${escapeHtml(title)}</title></head>`,
952
+ '<body style="font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0">',
953
+ '<div style="text-align:center">',
954
+ `<h1>${escapeHtml(title)}</h1>`,
955
+ `<p style="color:#666">${escapeHtml(body)}</p>`,
956
+ "</div></body></html>"
957
+ ].join("");
958
+ }
959
+
960
+ // ../mcp-oauth/dist/client/pkce.js
961
+ import crypto3 from "node:crypto";
962
+ function generateCodeVerifier() {
963
+ return crypto3.randomBytes(32).toString("base64url");
964
+ }
965
+ function generateCodeChallenge(verifier) {
966
+ return crypto3.createHash("sha256").update(verifier).digest("base64url");
967
+ }
968
+
969
+ // ../mcp-oauth/dist/client/token-endpoint.js
970
+ var MAX_JS_DATE_MS2 = 864e13;
971
+ var OAuthError = class extends Error {
972
+ error;
973
+ errorDescription;
974
+ errorUri;
975
+ error_description;
976
+ error_uri;
977
+ status;
978
+ retryable;
979
+ terminal;
980
+ constructor(shape, status) {
981
+ super(shape.error_description ?? shape.error);
982
+ this.name = "OAuthError";
983
+ this.error = shape.error;
984
+ this.errorDescription = shape.error_description;
985
+ this.errorUri = shape.error_uri;
986
+ this.error_description = shape.error_description;
987
+ this.error_uri = shape.error_uri;
988
+ this.status = status;
989
+ this.retryable = isRetryableOAuthError(this);
990
+ this.terminal = !this.retryable;
991
+ }
992
+ };
993
+ function isRetryableOAuthError(error) {
994
+ return error instanceof OAuthError && (error.status >= 500 || error.error === "server_error" || error.error === "temporarily_unavailable");
995
+ }
996
+ async function exchangeAuthorizationCode(input) {
997
+ const resource = canonicalizeResourceIndicator(input.resource);
998
+ return requestTokens({
999
+ tokenEndpoint: input.tokenEndpoint,
1000
+ clientId: input.clientId,
1001
+ clientSecret: input.clientSecret,
1002
+ params: {
1003
+ grant_type: "authorization_code",
1004
+ code: input.code,
1005
+ code_verifier: input.codeVerifier,
1006
+ redirect_uri: input.redirectUri,
1007
+ resource
1008
+ },
1009
+ fetch: input.fetch,
1010
+ now: input.now
1011
+ });
1012
+ }
1013
+ async function refreshAccessToken(input) {
1014
+ const resource = canonicalizeResourceIndicator(input.resource);
1015
+ return requestTokens({
1016
+ tokenEndpoint: input.tokenEndpoint,
1017
+ clientId: input.clientId,
1018
+ clientSecret: input.clientSecret,
1019
+ params: {
1020
+ grant_type: "refresh_token",
1021
+ refresh_token: input.refreshToken,
1022
+ resource
1023
+ },
1024
+ fetch: input.fetch,
1025
+ now: input.now
1026
+ });
1027
+ }
1028
+ async function requestTokens(input) {
1029
+ const body = new URLSearchParams({
1030
+ client_id: input.clientId,
1031
+ ...input.params
1032
+ });
1033
+ if (input.clientSecret !== void 0) {
1034
+ body.set("client_secret", input.clientSecret);
1035
+ }
1036
+ const response = await input.fetch(input.tokenEndpoint, {
1037
+ method: "POST",
1038
+ headers: {
1039
+ "Content-Type": "application/x-www-form-urlencoded"
1040
+ },
1041
+ body: body.toString()
1042
+ });
1043
+ const payload = await readOAuthJsonObjectResponse(response);
1044
+ const accessToken = getOwnEntry5(payload, "access_token");
1045
+ if (typeof accessToken !== "string" || accessToken.trim().length === 0) {
1046
+ throw new Error("OAuth token response missing access_token");
1047
+ }
1048
+ const normalizedAccessToken = accessToken.trim();
1049
+ const tokenType = normalizeBearerTokenType(getOwnEntry5(payload, "token_type"));
1050
+ if (tokenType === null) {
1051
+ throw new Error("OAuth token response missing token_type=Bearer");
1052
+ }
1053
+ const expiresIn = getOwnEntry5(payload, "expires_in");
1054
+ let expiresAt = null;
1055
+ if (expiresIn !== void 0) {
1056
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || !Number.isInteger(expiresIn) || expiresIn < 0) {
1057
+ throw new Error("OAuth token response has invalid expires_in");
1058
+ }
1059
+ expiresAt = input.now() + expiresIn * 1e3;
1060
+ if (!Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS2 || !Number.isFinite(new Date(expiresAt).getTime())) {
1061
+ throw new Error("OAuth token response has invalid expires_in");
1062
+ }
1063
+ }
1064
+ const refreshToken = getOwnEntry5(payload, "refresh_token");
1065
+ const scope = getOwnEntry5(payload, "scope");
1066
+ const normalizedRefreshToken = typeof refreshToken === "string" && refreshToken.trim().length > 0 ? refreshToken.trim() : void 0;
1067
+ const normalizedScope = typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : void 0;
1068
+ return {
1069
+ accessToken: normalizedAccessToken,
1070
+ refreshToken: normalizedRefreshToken === void 0 ? void 0 : normalizedRefreshToken,
1071
+ tokenType,
1072
+ expiresAt,
1073
+ scope: normalizedScope === void 0 ? void 0 : normalizedScope
1074
+ };
1075
+ }
1076
+ async function readOAuthJsonObjectResponse(response) {
1077
+ const fallbackError = createFallbackOAuthError(response.status);
1078
+ let payload;
1079
+ try {
1080
+ payload = await response.json();
1081
+ } catch {
1082
+ if (!response.ok) {
1083
+ throw fallbackError;
1084
+ }
1085
+ throw new Error("OAuth response must be a JSON object");
1086
+ }
1087
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
1088
+ if (!response.ok) {
1089
+ throw fallbackError;
1090
+ }
1091
+ throw new Error("OAuth response must be a JSON object");
1092
+ }
1093
+ const record = payload;
1094
+ if (!response.ok) {
1095
+ throw new OAuthError(readOAuthError(record, fallbackError.error), response.status);
1096
+ }
1097
+ return record;
1098
+ }
1099
+ function readOAuthError(payload, fallbackError = "server_error") {
1100
+ const error = getOwnEntry5(payload, "error");
1101
+ const errorDescription = getOwnEntry5(payload, "error_description");
1102
+ const errorUri = getOwnEntry5(payload, "error_uri");
1103
+ return {
1104
+ error: typeof error === "string" ? error : fallbackError,
1105
+ error_description: typeof errorDescription === "string" ? errorDescription : void 0,
1106
+ error_uri: typeof errorUri === "string" ? errorUri : void 0
1107
+ };
1108
+ }
1109
+ function getOwnEntry5(record, key2) {
1110
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
1111
+ }
1112
+ function createFallbackOAuthError(status) {
1113
+ const error = status === 503 ? "temporarily_unavailable" : "server_error";
1114
+ return new OAuthError({ error }, status);
1115
+ }
1116
+ function normalizeBearerTokenType(value) {
1117
+ if (typeof value !== "string") {
1118
+ return null;
1119
+ }
1120
+ return value.toLowerCase() === "bearer" ? "Bearer" : null;
1121
+ }
1122
+
1123
+ // ../mcp-oauth/dist/client/default-oauth-client-provider.js
1124
+ var MAX_JS_DATE_MS3 = 864e13;
1125
+ function createOAuthClientProvider(options) {
1126
+ if (isProviderOptions(options)) {
1127
+ return options.provider;
1128
+ }
1129
+ return createDefaultOAuthClientProvider(options);
1130
+ }
1131
+ function createDefaultOAuthClientProvider(options) {
1132
+ const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore);
1133
+ const clientStore = options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore);
1134
+ const now = options.now ?? Date.now;
1135
+ const registeredClients = /* @__PURE__ */ new Map();
1136
+ const refreshPromises = /* @__PURE__ */ new Map();
1137
+ const authorizationPromises = /* @__PURE__ */ new Map();
1138
+ return {
1139
+ async authorizeRequest(input) {
1140
+ assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
1141
+ const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
1142
+ const session = await ensureAuthorizedSession(requestUrl, void 0, input.fetch, false);
1143
+ const accessToken = session?.tokens?.accessToken;
1144
+ if (session === null || accessToken === void 0 || session.tokens === void 0 || isExpired(session.tokens, now)) {
1145
+ return;
1146
+ }
1147
+ assertRequestMatchesResource(requestUrl, session.resource);
1148
+ input.headers.set("Authorization", `Bearer ${accessToken}`);
1149
+ },
1150
+ async handleUnauthorized(input) {
1151
+ try {
1152
+ assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
1153
+ const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
1154
+ const resource = canonicalizeResourceIndicator(input.discovery.resource);
1155
+ assertRequestMatchesResource(requestUrl, resource);
1156
+ const forceRefresh = hasCachedAccessToken(await loadSession(resource)) && input.challenge?.params.error === "invalid_token";
1157
+ const session = await ensureAuthorizedSession(resource, {
1158
+ ...input.discovery,
1159
+ resource
1160
+ }, input.fetch, true, forceRefresh);
1161
+ if (session?.tokens?.accessToken === void 0) {
1162
+ return { action: "fail" };
1163
+ }
1164
+ return { action: "retry" };
1165
+ } catch (error) {
1166
+ return {
1167
+ action: "fail",
1168
+ error: error instanceof Error ? error : new Error(String(error))
1169
+ };
1170
+ }
1171
+ }
1172
+ };
1173
+ async function ensureAuthorizedSession(resource, discovery, fetch2, allowInteractive, forceRefresh = false) {
1174
+ const canonicalResource = canonicalizeResourceIndicator(resource);
1175
+ let session = await loadSession(canonicalResource);
1176
+ const sessionDiscovery = resolveDiscovery(discovery, session);
1177
+ if (session?.tokens !== void 0 && !forceRefresh && !isExpired(session.tokens, now)) {
1178
+ return session;
1179
+ }
1180
+ if (session?.tokens?.refreshToken !== void 0 && sessionDiscovery !== void 0 && (forceRefresh || isExpired(session.tokens, now))) {
1181
+ session = await refreshSession(canonicalResource, session, sessionDiscovery, fetch2);
1182
+ if (session?.tokens !== void 0 && !isExpired(session.tokens, now)) {
1183
+ return session;
1184
+ }
1185
+ }
1186
+ if (forceRefresh && session?.tokens !== void 0) {
1187
+ session = clearSessionTokens(session);
1188
+ await saveSession(canonicalResource, session);
1189
+ }
1190
+ if (!allowInteractive || sessionDiscovery === void 0) {
1191
+ return session;
1192
+ }
1193
+ return authorizeSession(canonicalResource, session, sessionDiscovery, fetch2);
1194
+ }
1195
+ async function refreshSession(resource, session, discovery, fetch2) {
1196
+ assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
1197
+ const inFlight = refreshPromises.get(resource);
1198
+ if (inFlight !== void 0) {
1199
+ return inFlight;
1200
+ }
1201
+ const promise = (async () => {
1202
+ try {
1203
+ if (session.tokens?.refreshToken === void 0) {
1204
+ return session;
1205
+ }
1206
+ let refreshAttempted = false;
1207
+ let refreshedTokens;
1208
+ while (true) {
1209
+ try {
1210
+ refreshedTokens = await refreshAccessToken({
1211
+ tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
1212
+ clientId: session.client.clientId,
1213
+ clientSecret: session.client.clientSecret,
1214
+ refreshToken: session.tokens.refreshToken,
1215
+ resource,
1216
+ fetch: fetch2,
1217
+ now
1218
+ });
1219
+ break;
1220
+ } catch (error) {
1221
+ if (error instanceof OAuthError && error.error === "invalid_grant") {
1222
+ const clearedSession = clearSessionTokens(session);
1223
+ await saveSession(resource, clearedSession);
1224
+ return clearedSession;
1225
+ }
1226
+ if (shouldReRegisterStoredDynamicClient(error, await loadRegisteredClient(discovery.authorizationServer), false)) {
1227
+ await clearRegisteredClient(discovery.authorizationServer);
1228
+ await clearSession(resource);
1229
+ return null;
1230
+ }
1231
+ if (!refreshAttempted && isRetryableOAuthError(error)) {
1232
+ refreshAttempted = true;
1233
+ continue;
1234
+ }
1235
+ throw error;
1236
+ }
1237
+ }
1238
+ const updatedSession = {
1239
+ ...session,
1240
+ tokens: {
1241
+ ...refreshedTokens,
1242
+ refreshToken: refreshedTokens.refreshToken ?? session.tokens.refreshToken
1243
+ },
1244
+ discovery: toStoredDiscovery(discovery)
1245
+ };
1246
+ await saveSession(resource, updatedSession);
1247
+ return updatedSession;
1248
+ } finally {
1249
+ refreshPromises.delete(resource);
1250
+ }
1251
+ })();
1252
+ refreshPromises.set(resource, promise);
1253
+ return promise;
1254
+ }
1255
+ async function authorizeSession(resource, existingSession, discovery, fetch2) {
1256
+ const inFlight = authorizationPromises.get(resource);
1257
+ if (inFlight !== void 0) {
1258
+ return inFlight;
1259
+ }
1260
+ const promise = (async () => {
1261
+ assertS256PkceSupport(discovery.authorizationServerMetadata);
1262
+ assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
1263
+ let currentSession = existingSession;
1264
+ let transientRetryAttempted = false;
1265
+ let reRegistrationAttempted = false;
1266
+ while (true) {
1267
+ const loopback = await createLoopbackAuthorizationSession({
1268
+ openBrowser: options.browser.openBrowser,
1269
+ readLine: options.browser.readLine,
1270
+ createServer: options.browser.createServer,
1271
+ landingPage: options.browser.landingPage
1272
+ });
1273
+ let resolvedClient = null;
1274
+ try {
1275
+ resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2);
1276
+ const sessionWithoutTokens = {
1277
+ resource,
1278
+ authorizationServer: discovery.authorizationServer,
1279
+ client: resolvedClient.client,
1280
+ discovery: toStoredDiscovery(discovery)
1281
+ };
1282
+ await saveSession(resource, sessionWithoutTokens);
1283
+ const verifier = generateCodeVerifier();
1284
+ const challenge = generateCodeChallenge(verifier);
1285
+ const authorizationUrl = buildAuthorizationUrl({
1286
+ metadata: discovery.authorizationServerMetadata,
1287
+ resource,
1288
+ clientId: resolvedClient.client.clientId,
1289
+ redirectUri: loopback.redirectUri,
1290
+ codeChallenge: challenge,
1291
+ clientMetadata: getClientMetadata(options.client)
1292
+ });
1293
+ const code = await loopback.waitForCode(authorizationUrl);
1294
+ const tokens = await exchangeAuthorizationCode({
1295
+ tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
1296
+ clientId: resolvedClient.client.clientId,
1297
+ clientSecret: resolvedClient.client.clientSecret,
1298
+ code,
1299
+ codeVerifier: verifier,
1300
+ redirectUri: loopback.redirectUri,
1301
+ resource,
1302
+ fetch: fetch2,
1303
+ now
1304
+ });
1305
+ const session = {
1306
+ ...sessionWithoutTokens,
1307
+ tokens
1308
+ };
1309
+ await saveSession(resource, session);
1310
+ return session;
1311
+ } catch (error) {
1312
+ if (shouldReRegisterStoredDynamicClient(error, resolvedClient, reRegistrationAttempted)) {
1313
+ reRegistrationAttempted = true;
1314
+ await clearRegisteredClient(discovery.authorizationServer);
1315
+ await clearSession(resource);
1316
+ currentSession = null;
1317
+ continue;
1318
+ }
1319
+ if (!transientRetryAttempted && isRetryableOAuthError(error)) {
1320
+ transientRetryAttempted = true;
1321
+ await clearSession(resource);
1322
+ currentSession = null;
1323
+ continue;
1324
+ }
1325
+ throw error;
1326
+ } finally {
1327
+ loopback.close();
1328
+ }
1329
+ }
1330
+ })();
1331
+ const finalPromise = promise.finally(() => {
1332
+ authorizationPromises.delete(resource);
1333
+ });
1334
+ authorizationPromises.set(resource, finalPromise);
1335
+ return finalPromise;
1336
+ }
1337
+ async function resolveClient(existingSession, discovery, redirectUri, fetch2) {
1338
+ const configuredClient = normalizeConfiguredClient(options.client);
1339
+ if (options.client.mode === "static") {
1340
+ if (configuredClient === null) {
1341
+ throw new Error("OAuth client_id must not be blank");
1342
+ }
1343
+ return {
1344
+ kind: "static",
1345
+ fromStoredRegistration: false,
1346
+ client: configuredClient
1347
+ };
1348
+ }
1349
+ const registrationEndpoint = getOwnString2(discovery.authorizationServerMetadata, "registration_endpoint");
1350
+ if (registrationEndpoint === void 0 && configuredClient !== null) {
1351
+ return {
1352
+ kind: "static",
1353
+ fromStoredRegistration: false,
1354
+ client: configuredClient
1355
+ };
1356
+ }
1357
+ const storedClient = await loadRegisteredClient(discovery.authorizationServer);
1358
+ if (storedClient !== null) {
1359
+ return {
1360
+ kind: "dynamic",
1361
+ fromStoredRegistration: true,
1362
+ client: storedClient
1363
+ };
1364
+ }
1365
+ if (registrationEndpoint === void 0) {
1366
+ if (existingSession !== null && existingSession.client.clientId.length > 0) {
1367
+ return {
1368
+ kind: "dynamic",
1369
+ fromStoredRegistration: true,
1370
+ client: existingSession.client
1371
+ };
1372
+ }
1373
+ throw new Error("Authorization server metadata is missing registration_endpoint");
1374
+ }
1375
+ if (existingSession !== null && existingSession.client.clientId.length > 0) {
1376
+ const isConfiguredStaticFallback = configuredClient !== null && existingSession.client.clientId === configuredClient.clientId && existingSession.client.clientSecret === configuredClient.clientSecret;
1377
+ if (!isConfiguredStaticFallback) {
1378
+ await saveRegisteredClient(discovery.authorizationServer, existingSession.client);
1379
+ return {
1380
+ kind: "dynamic",
1381
+ fromStoredRegistration: true,
1382
+ client: existingSession.client
1383
+ };
1384
+ }
1385
+ }
1386
+ const registrationBody = buildClientRegistrationBody(getClientMetadata(options.client), redirectUri);
1387
+ const response = await fetch2(registrationEndpoint, {
1388
+ method: "POST",
1389
+ headers: {
1390
+ "Content-Type": "application/json"
1391
+ },
1392
+ body: JSON.stringify(registrationBody)
1393
+ });
1394
+ const payload = await readOAuthJsonObjectResponse(response);
1395
+ const clientId = getOwnString2(payload, "client_id");
1396
+ if (clientId === void 0 || clientId.trim().length === 0) {
1397
+ throw new Error("OAuth client registration response missing client_id");
1398
+ }
1399
+ const clientSecret = getOwnString2(payload, "client_secret");
1400
+ const registeredClient = {
1401
+ clientId: clientId.trim(),
1402
+ clientSecret: clientSecret !== void 0 && clientSecret.trim().length > 0 ? clientSecret.trim() : void 0
1403
+ };
1404
+ await saveRegisteredClient(discovery.authorizationServer, registeredClient);
1405
+ return {
1406
+ kind: "dynamic",
1407
+ fromStoredRegistration: false,
1408
+ client: registeredClient
1409
+ };
1410
+ }
1411
+ async function loadSession(resource) {
1412
+ return normalizeLoadedSession(await sessionStore.load(resource));
1413
+ }
1414
+ async function saveSession(resource, session) {
1415
+ await sessionStore.save(resource, session);
1416
+ }
1417
+ async function clearSession(resource) {
1418
+ await sessionStore.clear(resource);
1419
+ }
1420
+ async function loadRegisteredClient(issuer) {
1421
+ if (registeredClients.has(issuer)) {
1422
+ return registeredClients.get(issuer) ?? null;
1423
+ }
1424
+ if (clientStore === null) {
1425
+ return null;
1426
+ }
1427
+ const client = await clientStore.load(issuer);
1428
+ const normalizedClient = client === null ? null : normalizeStoredClient(client);
1429
+ if (client !== null && normalizedClient === null) {
1430
+ await clientStore.clear(issuer);
1431
+ return null;
1432
+ }
1433
+ registeredClients.set(issuer, normalizedClient);
1434
+ return normalizedClient;
1435
+ }
1436
+ async function saveRegisteredClient(issuer, client) {
1437
+ registeredClients.set(issuer, client);
1438
+ if (clientStore !== null) {
1439
+ await clientStore.save(issuer, client);
1440
+ }
1441
+ }
1442
+ async function clearRegisteredClient(issuer) {
1443
+ registeredClients.delete(issuer);
1444
+ if (clientStore !== null) {
1445
+ await clientStore.clear(issuer);
1446
+ }
1447
+ }
1448
+ }
1449
+ function isProviderOptions(options) {
1450
+ return Object.prototype.hasOwnProperty.call(options, "provider");
1451
+ }
1452
+ function isExpired(tokens, now) {
1453
+ return tokens.expiresAt !== null && tokens.expiresAt <= now();
1454
+ }
1455
+ function resolveDiscovery(discovery, session) {
1456
+ if (discovery !== void 0) {
1457
+ return {
1458
+ ...discovery,
1459
+ resource: canonicalizeResourceIndicator(discovery.resource)
1460
+ };
1461
+ }
1462
+ if (session === null) {
1463
+ return void 0;
1464
+ }
1465
+ const metadata = session.discovery.authorizationServerMetadata;
1466
+ const issuer = getOwnString2(metadata, "issuer");
1467
+ const authorizationEndpoint = getOwnString2(metadata, "authorization_endpoint");
1468
+ const tokenEndpoint = getOwnString2(metadata, "token_endpoint");
1469
+ const codeChallengeMethodsSupported = getOwnStringArray(metadata, "code_challenge_methods_supported");
1470
+ if (issuer === void 0 || authorizationEndpoint === void 0 || tokenEndpoint === void 0 || codeChallengeMethodsSupported === void 0 || !codeChallengeMethodsSupported.includes("S256")) {
1471
+ return void 0;
1472
+ }
1473
+ return {
1474
+ resource: canonicalizeResourceIndicator(session.resource),
1475
+ resourceMetadataUrl: session.discovery.resourceMetadataUrl,
1476
+ resourceMetadata: session.discovery.resourceMetadata,
1477
+ authorizationServer: session.authorizationServer,
1478
+ authorizationServerMetadataUrl: "",
1479
+ authorizationServerMetadata: metadata
1480
+ };
1481
+ }
1482
+ function clearSessionTokens(session) {
1483
+ const nextSession = { ...session };
1484
+ delete nextSession.tokens;
1485
+ return nextSession;
1486
+ }
1487
+ function hasCachedAccessToken(session) {
1488
+ return session?.tokens?.accessToken !== void 0;
1489
+ }
1490
+ function normalizeLoadedSession(session) {
1491
+ if (session === null) {
1492
+ return null;
1493
+ }
1494
+ const client = normalizeStoredClient(getOwnEntry6(session, "client"));
1495
+ if (client === null) {
1496
+ return { ...session, client: { clientId: "" }, tokens: void 0 };
1497
+ }
1498
+ return {
1499
+ ...session,
1500
+ client,
1501
+ tokens: normalizeStoredTokens(getOwnEntry6(session, "tokens"))
1502
+ };
1503
+ }
1504
+ function normalizeStoredClient(value) {
1505
+ if (!isObjectRecord3(value)) {
1506
+ return null;
1507
+ }
1508
+ const clientId = getOwnString2(value, "clientId");
1509
+ if (clientId === void 0 || clientId.trim().length === 0) {
1510
+ return null;
1511
+ }
1512
+ const normalizedClientId = clientId.trim();
1513
+ const clientSecret = getOwnEntry6(value, "clientSecret");
1514
+ if (clientSecret === void 0) {
1515
+ return { clientId: normalizedClientId };
1516
+ }
1517
+ if (typeof clientSecret !== "string" || clientSecret.trim().length === 0) {
1518
+ return null;
1519
+ }
1520
+ const normalizedClientSecret = clientSecret.trim();
1521
+ return { clientId: normalizedClientId, clientSecret: normalizedClientSecret };
1522
+ }
1523
+ function normalizeStoredTokens(value) {
1524
+ if (value === void 0 || !isObjectRecord3(value)) {
1525
+ return void 0;
1526
+ }
1527
+ const accessToken = getOwnString2(value, "accessToken");
1528
+ const tokenType = getOwnString2(value, "tokenType");
1529
+ const expiresAt = getOwnEntry6(value, "expiresAt");
1530
+ const refreshToken = getOwnEntry6(value, "refreshToken");
1531
+ const scope = getOwnString2(value, "scope");
1532
+ const normalizedAccessToken = accessToken?.trim();
1533
+ const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken.trim() : void 0;
1534
+ const normalizedScope = scope?.trim();
1535
+ if (accessToken === void 0 || normalizedAccessToken === void 0 || normalizedAccessToken.length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isSafeInteger(expiresAt) && expiresAt <= MAX_JS_DATE_MS3 && Number.isFinite(new Date(expiresAt).getTime())) || refreshToken !== void 0 && (typeof refreshToken !== "string" || normalizedRefreshToken === void 0 || normalizedRefreshToken.length === 0)) {
1536
+ return void 0;
1537
+ }
1538
+ return {
1539
+ accessToken: normalizedAccessToken,
1540
+ tokenType,
1541
+ expiresAt,
1542
+ ...normalizedRefreshToken === void 0 ? {} : { refreshToken: normalizedRefreshToken },
1543
+ ...normalizedScope === void 0 || normalizedScope.length === 0 ? {} : { scope: normalizedScope }
1544
+ };
1545
+ }
1546
+ function getClientMetadata(client) {
1547
+ if (client.metadata === void 0) {
1548
+ return void 0;
1549
+ }
1550
+ return {
1551
+ clientName: normalizeOptionalOAuthString(client.metadata.clientName),
1552
+ scope: normalizeOptionalOAuthString(client.metadata.scope),
1553
+ softwareId: normalizeOptionalOAuthString(client.metadata.softwareId),
1554
+ softwareVersion: normalizeOptionalOAuthString(client.metadata.softwareVersion)
1555
+ };
1556
+ }
1557
+ function normalizeConfiguredClient(client) {
1558
+ const clientId = normalizeOptionalOAuthString(client.clientId);
1559
+ if (clientId === void 0) {
1560
+ return null;
1561
+ }
1562
+ const clientSecret = normalizeOptionalOAuthString(client.clientSecret);
1563
+ return clientSecret === void 0 ? { clientId } : { clientId, clientSecret };
1564
+ }
1565
+ function normalizeOptionalOAuthString(value) {
1566
+ if (value === void 0) {
1567
+ return void 0;
1568
+ }
1569
+ const trimmed = value.trim();
1570
+ return trimmed.length === 0 ? void 0 : trimmed;
1571
+ }
1572
+ function getOwnEntry6(record, key2) {
1573
+ return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
1574
+ }
1575
+ function isObjectRecord3(value) {
1576
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1577
+ }
1578
+ function getOwnString2(record, key2) {
1579
+ const value = getOwnEntry6(record, key2);
1580
+ return typeof value === "string" ? value : void 0;
1581
+ }
1582
+ function requireOwnString(record, key2, label) {
1583
+ const value = getOwnString2(record, key2);
1584
+ if (value === void 0) {
1585
+ throw new Error(`${label} is missing ${key2}`);
1586
+ }
1587
+ return value;
1588
+ }
1589
+ function getOwnStringArray(record, key2) {
1590
+ const value = getOwnEntry6(record, key2);
1591
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? value : void 0;
1592
+ }
1593
+ function buildAuthorizationUrl(input) {
1594
+ const authorizationEndpoint = requireOwnString(input.metadata, "authorization_endpoint", "Authorization server metadata");
1595
+ const issuer = requireOwnString(input.metadata, "issuer", "Authorization server metadata");
1596
+ const url = new URL2(authorizationEndpoint);
1597
+ const resource = canonicalizeResourceIndicator(input.resource);
1598
+ const state = createAuthorizationState({
1599
+ issuer,
1600
+ requireIssuer: getOwnEntry6(input.metadata, "authorization_response_iss_parameter_supported") === true
1601
+ });
1602
+ url.searchParams.set("response_type", "code");
1603
+ url.searchParams.set("client_id", input.clientId);
1604
+ url.searchParams.set("redirect_uri", input.redirectUri);
1605
+ url.searchParams.set("code_challenge", input.codeChallenge);
1606
+ url.searchParams.set("code_challenge_method", "S256");
1607
+ url.searchParams.set("resource", resource);
1608
+ url.searchParams.set("state", state);
1609
+ if (input.clientMetadata?.scope !== void 0 && input.clientMetadata.scope.length > 0) {
1610
+ url.searchParams.set("scope", input.clientMetadata.scope);
1611
+ }
1612
+ return url.toString();
1613
+ }
1614
+ function assertS256PkceSupport(metadata) {
1615
+ if (!getOwnStringArray(metadata, "code_challenge_methods_supported")?.includes("S256")) {
1616
+ throw new Error("Authorization server metadata must advertise code_challenge_methods_supported including S256");
1617
+ }
1618
+ }
1619
+ function normalizeHostname(hostname2) {
1620
+ return hostname2.endsWith(".") ? hostname2.slice(0, -1).toLowerCase() : hostname2.toLowerCase();
1621
+ }
1622
+ function isLoopbackHostname(hostname2) {
1623
+ const normalizedHostname = normalizeHostname(hostname2);
1624
+ return normalizedHostname === "localhost" || normalizedHostname === "::1" || normalizedHostname.startsWith("127.");
1625
+ }
1626
+ function assertSecureUrl(value, label) {
1627
+ const url = new URL2(value);
1628
+ if (url.protocol === "https:") {
1629
+ return;
1630
+ }
1631
+ if (url.protocol === "http:" && isLoopbackHostname(url.hostname)) {
1632
+ return;
1633
+ }
1634
+ throw new Error(`${label} must use https unless it targets a loopback host`);
1635
+ }
1636
+ function assertSecureOAuthFlowEndpoints(metadata) {
1637
+ const authorizationEndpoint = requireOwnString(metadata, "authorization_endpoint", "Authorization server metadata");
1638
+ const tokenEndpoint = requireOwnString(metadata, "token_endpoint", "Authorization server metadata");
1639
+ const registrationEndpoint = getOwnString2(metadata, "registration_endpoint");
1640
+ assertNoAccessTokenInUrl(authorizationEndpoint, "Authorization endpoint");
1641
+ assertNoAccessTokenInUrl(tokenEndpoint, "Token endpoint");
1642
+ assertSecureUrl(authorizationEndpoint, "Authorization endpoint");
1643
+ assertSecureUrl(tokenEndpoint, "Token endpoint");
1644
+ if (registrationEndpoint !== void 0) {
1645
+ assertNoAccessTokenInUrl(registrationEndpoint, "Registration endpoint");
1646
+ assertSecureUrl(registrationEndpoint, "Registration endpoint");
1647
+ }
1648
+ }
1649
+ function assertNoAccessTokenInUrl(value, label) {
1650
+ const url = value instanceof URL2 ? new URL2(value.toString()) : new URL2(value);
1651
+ if (url.searchParams.has("access_token")) {
1652
+ throw new Error(`${label} must not include access_token in the URI`);
1653
+ }
1654
+ }
1655
+ function assertRequestMatchesResource(requestUrl, resource) {
1656
+ if (requestUrl !== resource) {
1657
+ throw new Error(`OAuth request URL ${requestUrl} does not match discovered resource ${resource}`);
1658
+ }
1659
+ }
1660
+ function buildClientRegistrationBody(metadata, redirectUri) {
1661
+ const body = {
1662
+ redirect_uris: [redirectUri],
1663
+ grant_types: ["authorization_code", "refresh_token"],
1664
+ response_types: ["code"],
1665
+ token_endpoint_auth_method: "none"
1666
+ };
1667
+ const clientName = metadata === void 0 ? void 0 : getOwnString2(metadata, "clientName");
1668
+ const scope = metadata === void 0 ? void 0 : getOwnString2(metadata, "scope");
1669
+ const softwareId = metadata === void 0 ? void 0 : getOwnString2(metadata, "softwareId");
1670
+ const softwareVersion = metadata === void 0 ? void 0 : getOwnString2(metadata, "softwareVersion");
1671
+ if (clientName !== void 0 && clientName.length > 0) {
1672
+ body.client_name = clientName;
1673
+ }
1674
+ if (scope !== void 0 && scope.length > 0) {
1675
+ body.scope = scope;
1676
+ }
1677
+ if (softwareId !== void 0 && softwareId.length > 0) {
1678
+ body.software_id = softwareId;
1679
+ }
1680
+ if (softwareVersion !== void 0 && softwareVersion.length > 0) {
1681
+ body.software_version = softwareVersion;
1682
+ }
1683
+ return body;
1684
+ }
1685
+ function toStoredDiscovery(discovery) {
1686
+ return {
1687
+ resourceMetadataUrl: discovery.resourceMetadataUrl,
1688
+ resourceMetadata: discovery.resourceMetadata,
1689
+ authorizationServerMetadata: discovery.authorizationServerMetadata
1690
+ };
1691
+ }
1692
+ function shouldReRegisterStoredDynamicClient(error, client, alreadyAttempted) {
1693
+ if (!(error instanceof OAuthError) || error.error !== "invalid_client" || alreadyAttempted) {
1694
+ return false;
1695
+ }
1696
+ if (client === null) {
1697
+ return false;
1698
+ }
1699
+ if ("kind" in client) {
1700
+ return client.kind === "dynamic" && client.fromStoredRegistration;
1701
+ }
1702
+ return true;
1703
+ }
1704
+
1705
+ // src/oauth-discovery.ts
1706
+ function defaultOAuthMetadataFetch(input, init) {
1707
+ return fetch(input, init);
1708
+ }
1709
+ function isObjectRecord4(value) {
1710
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1711
+ }
1712
+ function isStringArray(value) {
1713
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
1714
+ }
1715
+ function normalizeHostname2(hostname2) {
1716
+ return hostname2.endsWith(".") ? hostname2.slice(0, -1).toLowerCase() : hostname2.toLowerCase();
1717
+ }
1718
+ function isLoopbackHostname2(hostname2) {
1719
+ const normalizedHostname = normalizeHostname2(hostname2);
1720
+ return normalizedHostname === "localhost" || normalizedHostname === "::1" || normalizedHostname.startsWith("127.");
1721
+ }
1722
+ function assertSecureUrl2(url, label) {
1723
+ if (url.protocol === "https:") {
1724
+ return;
1725
+ }
1726
+ if (url.protocol === "http:" && isLoopbackHostname2(url.hostname)) {
1727
+ return;
1728
+ }
1729
+ throw new Error(`${label} must use https unless it targets a loopback host`);
1730
+ }
1731
+ function validateProtectedResourceMetadata(value, resourceUrl) {
1732
+ if (!isObjectRecord4(value)) {
1733
+ throw new Error("Protected resource metadata must be a JSON object");
1734
+ }
1735
+ if (typeof value.resource !== "string" || value.resource.length === 0) {
1736
+ throw new Error("Protected resource metadata must include a resource string");
1737
+ }
1738
+ const normalizedResource = canonicalizeResourceIndicator(value.resource);
1739
+ if (normalizedResource !== resourceUrl) {
1740
+ throw new Error(
1741
+ `Protected resource metadata resource mismatch: expected ${resourceUrl}, received ${value.resource}`
1742
+ );
1743
+ }
1744
+ if (!isStringArray(value.authorization_servers) || value.authorization_servers.length === 0) {
1745
+ throw new Error(
1746
+ "Protected resource metadata must include a non-empty authorization_servers array"
1747
+ );
1748
+ }
1749
+ return {
1750
+ ...value,
1751
+ resource: normalizedResource
1752
+ };
1753
+ }
1754
+ function validateAuthorizationServerMetadata(value, issuer) {
1755
+ if (!isObjectRecord4(value)) {
1756
+ throw new Error("Authorization server metadata must be a JSON object");
1757
+ }
1758
+ if (typeof value.issuer !== "string" || value.issuer.length === 0) {
1759
+ throw new Error("Authorization server metadata must include issuer");
1760
+ }
1761
+ if (value.issuer !== issuer) {
1762
+ throw new Error(
1763
+ `Authorization server metadata issuer mismatch: expected ${issuer}, received ${value.issuer}`
1764
+ );
1765
+ }
1766
+ if (typeof value.authorization_endpoint !== "string" || value.authorization_endpoint.length === 0) {
1767
+ throw new Error("Authorization server metadata must include authorization_endpoint");
1768
+ }
1769
+ if (typeof value.token_endpoint !== "string" || value.token_endpoint.length === 0) {
1770
+ throw new Error("Authorization server metadata must include token_endpoint");
1771
+ }
1772
+ if (!isStringArray(value.response_types_supported) || !value.response_types_supported.includes("code")) {
1773
+ throw new Error(
1774
+ "Authorization server metadata must include response_types_supported containing code"
1775
+ );
1776
+ }
1777
+ if (!isStringArray(value.code_challenge_methods_supported) || !value.code_challenge_methods_supported.includes("S256")) {
1778
+ throw new Error(
1779
+ "Authorization server metadata must include code_challenge_methods_supported containing S256"
1780
+ );
1781
+ }
1782
+ return value;
1783
+ }
1784
+ async function readJsonResponse(response, label) {
1785
+ if (!response.ok) {
1786
+ const statusDescriptor = `${response.status} ${response.statusText}`.trim();
1787
+ throw new Error(`${label} request failed (${statusDescriptor})`);
1788
+ }
1789
+ try {
1790
+ return await response.json();
1791
+ } catch {
1792
+ throw new Error(`${label} response must be valid JSON`);
1793
+ }
1794
+ }
1795
+ function resolveWellKnownMetadataUrl(inputUrl, suffix) {
1796
+ const url = new URL(typeof inputUrl === "string" ? inputUrl : inputUrl.toString());
1797
+ const resourcePath = url.pathname === "/" ? "" : url.pathname;
1798
+ url.pathname = `/.well-known/${suffix}${resourcePath}`;
1799
+ return url.toString();
1800
+ }
1801
+ function resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl) {
1802
+ const resource = new URL(canonicalizeResourceIndicator(resourceUrl));
1803
+ assertSecureUrl2(resource, "Protected resource URL");
1804
+ if (resourceMetadataUrl !== void 0) {
1805
+ const resolvedResourceMetadataUrl2 = new URL(
1806
+ typeof resourceMetadataUrl === "string" ? resourceMetadataUrl : resourceMetadataUrl.toString(),
1807
+ resource
1808
+ );
1809
+ assertSecureUrl2(resolvedResourceMetadataUrl2, "Protected resource metadata URL");
1810
+ return resolvedResourceMetadataUrl2.toString();
1811
+ }
1812
+ const resolvedResourceMetadataUrl = new URL(
1813
+ resolveWellKnownMetadataUrl(resource, "oauth-protected-resource")
1814
+ );
1815
+ assertSecureUrl2(resolvedResourceMetadataUrl, "Protected resource metadata URL");
1816
+ return resolvedResourceMetadataUrl.toString();
1817
+ }
1818
+ function normalizeAuthorizationServerIssuer(issuer) {
1819
+ const input = typeof issuer === "string" ? issuer : issuer.toString();
1820
+ const url = new URL(input);
1821
+ if (url.search.length > 0 || url.hash.length > 0) {
1822
+ throw new Error("Authorization server issuer must not include query or fragment");
1823
+ }
1824
+ assertSecureUrl2(url, "Authorization server issuer");
1825
+ if (url.pathname.length > 1 && url.pathname.endsWith("/")) {
1826
+ url.pathname = url.pathname.slice(0, -1);
1827
+ }
1828
+ return url.pathname === "/" ? url.origin : url.toString();
1829
+ }
1830
+ function resolveAuthorizationServerMetadataUrl(issuer) {
1831
+ return resolveWellKnownMetadataUrl(
1832
+ normalizeAuthorizationServerIssuer(issuer),
1833
+ "oauth-authorization-server"
1834
+ );
1835
+ }
1836
+ var OAuthMetadataDiscovery = class {
1837
+ fetchImpl;
1838
+ cache;
1839
+ memoryCache = /* @__PURE__ */ new Map();
1840
+ constructor({ fetch: fetch2 = defaultOAuthMetadataFetch, cache } = {}) {
1841
+ this.fetchImpl = fetch2;
1842
+ this.cache = cache;
1843
+ }
1844
+ async discover(resourceUrl, { resourceMetadataUrl } = {}) {
1845
+ const cacheKey = canonicalizeResourceIndicator(resourceUrl);
1846
+ const resourceMetadataLocation = resolveProtectedResourceMetadataUrl(
1847
+ cacheKey,
1848
+ resourceMetadataUrl
1849
+ );
1850
+ const memoryCachedResult = this.memoryCache.get(cacheKey);
1851
+ if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
1852
+ return memoryCachedResult;
1853
+ }
1854
+ const sharedCachedResult = await this.cache?.get(cacheKey);
1855
+ if (sharedCachedResult !== null && sharedCachedResult !== void 0 && resourceMetadataUrl === void 0) {
1856
+ this.memoryCache.set(cacheKey, sharedCachedResult);
1857
+ return sharedCachedResult;
1858
+ }
1859
+ const resourceMetadataResponse = await this.fetchImpl(resourceMetadataLocation, {
1860
+ method: "GET",
1861
+ headers: {
1862
+ Accept: "application/json"
1863
+ }
1864
+ });
1865
+ const resourceMetadata = validateProtectedResourceMetadata(
1866
+ await readJsonResponse(resourceMetadataResponse, "Protected resource metadata"),
1867
+ cacheKey
1868
+ );
1869
+ const authorizationServerErrors = [];
1870
+ for (const authorizationServer of resourceMetadata.authorization_servers) {
1871
+ const normalizedAuthorizationServer = normalizeAuthorizationServerIssuer(
1872
+ authorizationServer
1873
+ );
1874
+ const authorizationServerMetadataUrl = resolveAuthorizationServerMetadataUrl(normalizedAuthorizationServer);
1875
+ try {
1876
+ const authorizationServerResponse = await this.fetchImpl(authorizationServerMetadataUrl, {
1877
+ method: "GET",
1878
+ headers: {
1879
+ Accept: "application/json"
1880
+ }
1881
+ });
1882
+ const authorizationServerMetadata = validateAuthorizationServerMetadata(
1883
+ await readJsonResponse(
1884
+ authorizationServerResponse,
1885
+ "Authorization server metadata"
1886
+ ),
1887
+ normalizedAuthorizationServer
1888
+ );
1889
+ const result = {
1890
+ resource: resourceMetadata.resource,
1891
+ resourceMetadataUrl: resourceMetadataLocation,
1892
+ resourceMetadata,
1893
+ authorizationServer: normalizedAuthorizationServer,
1894
+ authorizationServerMetadataUrl,
1895
+ authorizationServerMetadata
1896
+ };
1897
+ this.memoryCache.set(cacheKey, result);
1898
+ await this.cache?.set(cacheKey, result);
1899
+ return result;
1900
+ } catch (error) {
1901
+ authorizationServerErrors.push(
1902
+ `${authorizationServerMetadataUrl}: ${error instanceof Error ? error.message : String(error)}`
1903
+ );
1904
+ }
1905
+ }
1906
+ throw new Error(
1907
+ `Unable to load authorization server metadata for ${cacheKey}: ${authorizationServerErrors.join(
1908
+ "; "
1909
+ )}`
1910
+ );
1911
+ }
1912
+ };
1913
+ async function discoverOAuthMetadata(resourceUrl, options = {}) {
1914
+ const discovery = new OAuthMetadataDiscovery(options);
1915
+ return discovery.discover(resourceUrl, options);
1916
+ }
1917
+ function skipOptionalWhitespace(value, start) {
1918
+ let index = start;
1919
+ while (index < value.length && (value[index] === " " || value[index] === " ")) {
1920
+ index += 1;
1921
+ }
1922
+ return index;
1923
+ }
1924
+ function readToken(value, start) {
1925
+ let index = start;
1926
+ while (index < value.length) {
1927
+ const character = value[index];
1928
+ if (character === " " || character === " " || character === "," || character === "=" || character === '"') {
1929
+ break;
1930
+ }
1931
+ index += 1;
1932
+ }
1933
+ if (index === start) {
1934
+ return null;
1935
+ }
1936
+ return {
1937
+ token: value.slice(start, index),
1938
+ nextIndex: index
1939
+ };
1940
+ }
1941
+ function looksLikeAuthParam(value, start) {
1942
+ const token = readToken(value, start);
1943
+ if (token === null) {
1944
+ return false;
1945
+ }
1946
+ return value[skipOptionalWhitespace(value, token.nextIndex)] === "=";
1947
+ }
1948
+ function isToken68Character(character) {
1949
+ return character >= "a" && character <= "z" || character >= "A" && character <= "Z" || character >= "0" && character <= "9" || character === "-" || character === "." || character === "_" || character === "~" || character === "+" || character === "/";
1950
+ }
1951
+ function readToken68(value, start) {
1952
+ let nextIndex = start;
1953
+ while (nextIndex < value.length) {
1954
+ const character = value[nextIndex];
1955
+ if (character === "," || character === " " || character === " ") {
1956
+ break;
1957
+ }
1958
+ nextIndex += 1;
1959
+ }
1960
+ const token68 = value.slice(start, nextIndex);
1961
+ if (token68.length === 0) {
1962
+ return null;
1963
+ }
1964
+ let index = 0;
1965
+ while (index < token68.length && isToken68Character(token68[index])) {
1966
+ index += 1;
1967
+ }
1968
+ if (index === 0) {
1969
+ return null;
1970
+ }
1971
+ while (index < token68.length && token68[index] === "=") {
1972
+ index += 1;
1973
+ }
1974
+ if (index !== token68.length) {
1975
+ return null;
1976
+ }
1977
+ return { token68, nextIndex };
1978
+ }
1979
+ function readQuotedString(value, start) {
1980
+ if (value[start] !== '"') {
1981
+ return null;
1982
+ }
1983
+ let parsedValue = "";
1984
+ let index = start + 1;
1985
+ let escaping = false;
1986
+ while (index < value.length) {
1987
+ const character = value[index];
1988
+ if (escaping) {
1989
+ parsedValue += character;
1990
+ escaping = false;
1991
+ index += 1;
1992
+ continue;
1993
+ }
1994
+ if (character === "\\") {
1995
+ escaping = true;
1996
+ index += 1;
1997
+ continue;
1998
+ }
1999
+ if (character === '"') {
2000
+ return {
2001
+ parsedValue,
2002
+ nextIndex: index + 1
2003
+ };
2004
+ }
2005
+ parsedValue += character;
2006
+ index += 1;
2007
+ }
2008
+ return null;
2009
+ }
2010
+ function parseAuthParam(value, start) {
2011
+ const token = readToken(value, start);
2012
+ if (token === null) {
2013
+ return null;
2014
+ }
2015
+ let index = skipOptionalWhitespace(value, token.nextIndex);
2016
+ if (value[index] !== "=") {
2017
+ return null;
2018
+ }
2019
+ index = skipOptionalWhitespace(value, index + 1);
2020
+ if (index >= value.length) {
2021
+ return null;
2022
+ }
2023
+ const quotedValue = readQuotedString(value, index);
2024
+ if (quotedValue !== null) {
2025
+ return {
2026
+ name: token.token,
2027
+ value: quotedValue.parsedValue,
2028
+ nextIndex: quotedValue.nextIndex
2029
+ };
2030
+ }
2031
+ let nextIndex = index;
2032
+ while (nextIndex < value.length) {
2033
+ const character = value[nextIndex];
2034
+ if (character === "," || character === " " || character === " ") {
2035
+ break;
2036
+ }
2037
+ nextIndex += 1;
2038
+ }
2039
+ return {
2040
+ name: token.token,
2041
+ value: value.slice(index, nextIndex),
2042
+ nextIndex
2043
+ };
2044
+ }
2045
+ function parseBearerWwwAuthenticateHeader(headerValue) {
2046
+ if (headerValue === null) {
2047
+ return null;
2048
+ }
2049
+ let index = 0;
2050
+ let firstBearerChallenge = null;
2051
+ while (index < headerValue.length) {
2052
+ index = skipOptionalWhitespace(headerValue, index);
2053
+ while (headerValue[index] === ",") {
2054
+ index = skipOptionalWhitespace(headerValue, index + 1);
2055
+ }
2056
+ const scheme = readToken(headerValue, index);
2057
+ if (scheme === null) {
2058
+ break;
2059
+ }
2060
+ index = skipOptionalWhitespace(headerValue, scheme.nextIndex);
2061
+ const params = /* @__PURE__ */ Object.create(null);
2062
+ if (index < headerValue.length && headerValue[index] !== ",") {
2063
+ const token68 = readToken68(headerValue, index);
2064
+ if (token68 !== null) {
2065
+ index = token68.nextIndex;
2066
+ } else if (looksLikeAuthParam(headerValue, index)) {
2067
+ while (index < headerValue.length) {
2068
+ const parsedParam = parseAuthParam(headerValue, index);
2069
+ if (parsedParam === null) {
2070
+ break;
2071
+ }
2072
+ params[parsedParam.name] = parsedParam.value;
2073
+ index = skipOptionalWhitespace(headerValue, parsedParam.nextIndex);
2074
+ if (headerValue[index] !== ",") {
2075
+ break;
2076
+ }
2077
+ const nextIndex = skipOptionalWhitespace(headerValue, index + 1);
2078
+ if (!looksLikeAuthParam(headerValue, nextIndex)) {
2079
+ index = nextIndex;
2080
+ break;
2081
+ }
2082
+ index = nextIndex;
2083
+ }
2084
+ }
2085
+ }
2086
+ if (scheme.token.toLowerCase() === "bearer") {
2087
+ const challenge = {
2088
+ scheme: "Bearer",
2089
+ params,
2090
+ raw: headerValue
2091
+ };
2092
+ if (Object.keys(params).length > 0) {
2093
+ return challenge;
2094
+ }
2095
+ firstBearerChallenge ??= challenge;
2096
+ }
2097
+ if (headerValue[index] === ",") {
2098
+ index += 1;
2099
+ }
2100
+ }
2101
+ return firstBearerChallenge;
2102
+ }
2103
+
2104
+ // src/internal.ts
2105
+ var MCP_PROTOCOL_VERSION = "2025-03-26";
2106
+ var McpClient = class {
2107
+ currentState = "disconnected";
2108
+ currentServerCapabilities = null;
2109
+ currentClientCapabilities = null;
2110
+ currentServerInfo = null;
2111
+ currentInstructions;
2112
+ subscribedResourceUris = /* @__PURE__ */ new Set();
2113
+ activeProgressTokens = /* @__PURE__ */ new Map();
2114
+ options;
2115
+ transport = null;
2116
+ messageLayer = null;
2117
+ constructor(options) {
2118
+ this.options = options;
2119
+ }
2120
+ get state() {
2121
+ return this.currentState;
2122
+ }
2123
+ get serverCapabilities() {
2124
+ return this.currentServerCapabilities === null ? null : structuredClone(this.currentServerCapabilities);
2125
+ }
2126
+ get serverInfo() {
2127
+ return this.currentServerInfo;
2128
+ }
2129
+ get instructions() {
2130
+ return this.currentInstructions;
2131
+ }
2132
+ getMessageLayerOrThrow() {
2133
+ if (this.currentState === "disconnected") {
2134
+ throw new Error("MCP client is disconnected");
2135
+ }
2136
+ if (this.currentState === "closed") {
2137
+ throw new Error("MCP client is closed");
2138
+ }
2139
+ if (this.messageLayer === null) {
2140
+ throw new Error("MCP client is disconnected");
2141
+ }
2142
+ return this.messageLayer;
2143
+ }
2144
+ async connect(transport) {
2145
+ if (this.currentState !== "disconnected" && this.currentState !== "closed") {
2146
+ throw new Error("MCP client is already connected");
2147
+ }
2148
+ this.currentServerCapabilities = null;
2149
+ this.currentClientCapabilities = null;
2150
+ this.currentServerInfo = null;
2151
+ this.currentInstructions = void 0;
2152
+ this.subscribedResourceUris.clear();
2153
+ this.activeProgressTokens.clear();
2154
+ const transportClosedReason = transport.closed.then((closedEvent) => closedEvent.reason).catch(
2155
+ (error) => error instanceof Error ? error : new Error(String(error))
2156
+ );
2157
+ const messageLayer = new JsonRpcMessageLayer(
2158
+ transport.readable,
2159
+ transport.writable,
2160
+ this.options.requestTimeoutMs,
2161
+ transportClosedReason
2162
+ );
2163
+ const {
2164
+ onSamplingRequest,
2165
+ onRootsList,
2166
+ onToolsChanged,
2167
+ onResourcesChanged,
2168
+ onResourceUpdated,
2169
+ onPromptsChanged,
2170
+ onLog,
2171
+ onProgress
2172
+ } = this.options;
2173
+ messageLayer.onRequest("ping", () => ({}));
2174
+ if (onSamplingRequest !== void 0) {
2175
+ messageLayer.onRequest(
2176
+ "sampling/createMessage",
2177
+ (params) => onSamplingRequest(params)
2178
+ );
2179
+ }
2180
+ messageLayer.onNotification("notifications/tools/list_changed", async () => {
2181
+ if (onToolsChanged === void 0 || this.currentServerCapabilities?.tools?.listChanged !== true) {
2182
+ return;
2183
+ }
2184
+ await onToolsChanged();
2185
+ });
2186
+ messageLayer.onNotification("notifications/resources/list_changed", async () => {
2187
+ if (onResourcesChanged === void 0 || this.currentServerCapabilities?.resources?.listChanged !== true) {
2188
+ return;
2189
+ }
2190
+ await onResourcesChanged();
2191
+ });
2192
+ messageLayer.onNotification("notifications/resources/updated", async (params) => {
2193
+ if (onResourceUpdated === void 0) {
2194
+ return;
2195
+ }
2196
+ if (typeof params !== "object" || params === null || Array.isArray(params)) {
2197
+ return;
2198
+ }
2199
+ const { uri } = params;
2200
+ if (typeof uri !== "string" || !this.subscribedResourceUris.has(uri)) {
2201
+ return;
2202
+ }
2203
+ await onResourceUpdated(uri);
2204
+ });
2205
+ messageLayer.onNotification("notifications/prompts/list_changed", async () => {
2206
+ if (onPromptsChanged === void 0 || this.currentServerCapabilities?.prompts?.listChanged !== true) {
2207
+ return;
2208
+ }
2209
+ await onPromptsChanged();
2210
+ });
2211
+ messageLayer.onNotification("notifications/message", async (params) => {
2212
+ if (onLog === void 0 || !isObjectRecord5(params) || !isLogLevel(params.level)) {
2213
+ return;
2214
+ }
2215
+ if (!hasOwn(params, "data")) {
2216
+ return;
2217
+ }
2218
+ const message = {
2219
+ level: params.level,
2220
+ data: params.data
2221
+ };
2222
+ if (params.logger !== void 0) {
2223
+ if (typeof params.logger !== "string") {
2224
+ return;
2225
+ }
2226
+ message.logger = params.logger;
2227
+ }
2228
+ await onLog(message);
2229
+ });
2230
+ messageLayer.onNotification("notifications/progress", async (params) => {
2231
+ if (onProgress === void 0 || !isObjectRecord5(params)) {
2232
+ return;
2233
+ }
2234
+ const { progressToken, progress } = params;
2235
+ if (!isRequestId(progressToken) || typeof progress !== "number" || !this.activeProgressTokens.has(progressToken)) {
2236
+ return;
2237
+ }
2238
+ const progressParams = {
2239
+ progressToken,
2240
+ progress
2241
+ };
2242
+ if (params.total !== void 0) {
2243
+ if (typeof params.total !== "number") {
2244
+ return;
2245
+ }
2246
+ progressParams.total = params.total;
2247
+ }
2248
+ if (params.message !== void 0) {
2249
+ if (typeof params.message !== "string") {
2250
+ return;
2251
+ }
2252
+ progressParams.message = params.message;
2253
+ }
2254
+ await onProgress(progressParams);
2255
+ });
2256
+ messageLayer.onNotification("notifications/cancelled", () => void 0);
2257
+ this.transport = transport;
2258
+ this.messageLayer = messageLayer;
2259
+ this.currentState = "initializing";
2260
+ this.subscribedResourceUris.clear();
2261
+ this.activeProgressTokens.clear();
2262
+ transport.closed.then((closedEvent) => {
2263
+ if (this.transport !== transport) {
2264
+ return;
2265
+ }
2266
+ this.messageLayer?.dispose(closedEvent.reason);
2267
+ this.messageLayer = null;
2268
+ this.transport = null;
2269
+ this.currentState = "closed";
2270
+ }).catch((error) => {
2271
+ if (this.transport !== transport) {
2272
+ return;
2273
+ }
2274
+ const reason = error instanceof Error ? error : new Error(String(error));
2275
+ this.messageLayer?.dispose(reason);
2276
+ this.messageLayer = null;
2277
+ this.transport = null;
2278
+ this.currentState = "closed";
2279
+ });
2280
+ const capabilities = {
2281
+ ...this.options.capabilities ?? {}
2282
+ };
2283
+ if (onSamplingRequest !== void 0 && capabilities.sampling === void 0) {
2284
+ capabilities.sampling = {};
2285
+ }
2286
+ if (onRootsList !== void 0) {
2287
+ capabilities.roots = {
2288
+ ...capabilities.roots ?? {}
2289
+ };
2290
+ }
2291
+ this.currentClientCapabilities = structuredClone(capabilities);
2292
+ try {
2293
+ const initializeResultValue = await messageLayer.sendRequest("initialize", {
2294
+ protocolVersion: MCP_PROTOCOL_VERSION,
2295
+ clientInfo: this.options.clientInfo,
2296
+ capabilities
2297
+ });
2298
+ if (!isInitializeResult(initializeResultValue)) {
2299
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid initialize result");
2300
+ }
2301
+ const initializeResult = initializeResultValue;
2302
+ if (initializeResult.protocolVersion !== MCP_PROTOCOL_VERSION) {
2303
+ throw new McpError(
2304
+ ERROR_INVALID_REQUEST,
2305
+ `Unsupported protocol version: ${initializeResult.protocolVersion}`
2306
+ );
2307
+ }
2308
+ this.currentServerCapabilities = structuredClone(initializeResult.capabilities);
2309
+ this.currentServerInfo = { ...initializeResult.serverInfo };
2310
+ this.currentInstructions = initializeResult.instructions;
2311
+ if (onRootsList !== void 0) {
2312
+ messageLayer.onRequest("roots/list", async () => ({
2313
+ roots: await onRootsList()
2314
+ }));
2315
+ }
2316
+ messageLayer.sendNotification("notifications/initialized");
2317
+ this.currentState = "ready";
2318
+ return initializeResult;
2319
+ } catch (error) {
2320
+ if (this.transport === transport) {
2321
+ const reason = error instanceof Error ? error : new Error(String(error));
2322
+ messageLayer.dispose(reason);
2323
+ transport.dispose(reason);
2324
+ this.messageLayer = null;
2325
+ this.transport = null;
2326
+ this.currentState = "disconnected";
2327
+ }
2328
+ throw error;
2329
+ }
2330
+ }
2331
+ getServerCapabilitiesOrThrow() {
2332
+ if (this.currentServerCapabilities === null) {
2333
+ throw new Error("MCP client has not completed initialization");
2334
+ }
2335
+ return this.currentServerCapabilities;
2336
+ }
2337
+ async listTools(params = {}) {
2338
+ const messageLayer = this.getMessageLayerOrThrow();
2339
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2340
+ if (serverCapabilities.tools === void 0) {
2341
+ throw new Error("Server does not support tools");
2342
+ }
2343
+ const requestParams = params.cursor === void 0 ? void 0 : { cursor: params.cursor };
2344
+ const result = await messageLayer.sendRequest("tools/list", requestParams);
2345
+ if (!isToolsListResult(result)) {
2346
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid tools/list result");
2347
+ }
2348
+ return result;
2349
+ }
2350
+ async callTool(params, options = {}) {
2351
+ const messageLayer = this.getMessageLayerOrThrow();
2352
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2353
+ if (serverCapabilities.tools === void 0) {
2354
+ throw new Error("Server does not support tools");
2355
+ }
2356
+ if (options.signal?.aborted) {
2357
+ throw options.signal.reason;
2358
+ }
2359
+ const requestParams = options.progressToken === void 0 ? params : {
2360
+ ...params,
2361
+ _meta: {
2362
+ progressToken: options.progressToken
2363
+ }
2364
+ };
2365
+ if (options.progressToken !== void 0) {
2366
+ this.activeProgressTokens.set(
2367
+ options.progressToken,
2368
+ (this.activeProgressTokens.get(options.progressToken) ?? 0) + 1
2369
+ );
2370
+ }
2371
+ try {
2372
+ let requestId;
2373
+ let cancellationSent = false;
2374
+ const sendCancellationNotification = () => {
2375
+ if (requestId === void 0 || cancellationSent) {
2376
+ return;
2377
+ }
2378
+ cancellationSent = true;
2379
+ messageLayer.sendNotification("notifications/cancelled", { requestId });
2380
+ };
2381
+ const requestPromise = messageLayer.sendRequest("tools/call", requestParams, {
2382
+ onRequestId: (nextRequestId) => {
2383
+ requestId = nextRequestId;
2384
+ },
2385
+ onTimeout: sendCancellationNotification
2386
+ }).then((result) => {
2387
+ if (!isCallToolResult(result)) {
2388
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid tool result");
2389
+ }
2390
+ return result;
2391
+ });
2392
+ if (options.signal === void 0) {
2393
+ return await requestPromise;
2394
+ }
2395
+ const signal = options.signal;
2396
+ let abortListener;
2397
+ const abortPromise = new Promise((_, reject) => {
2398
+ const rejectWithAbortReason = () => {
2399
+ sendCancellationNotification();
2400
+ if (requestId !== void 0) {
2401
+ messageLayer.cancelRequest(requestId, signal.reason);
2402
+ }
2403
+ reject(signal.reason);
2404
+ };
2405
+ abortListener = rejectWithAbortReason;
2406
+ signal.addEventListener("abort", abortListener, { once: true });
2407
+ if (signal.aborted) {
2408
+ signal.removeEventListener("abort", abortListener);
2409
+ rejectWithAbortReason();
2410
+ }
2411
+ });
2412
+ try {
2413
+ return await Promise.race([requestPromise, abortPromise]);
2414
+ } finally {
2415
+ if (abortListener !== void 0) {
2416
+ signal.removeEventListener("abort", abortListener);
2417
+ }
2418
+ }
2419
+ } finally {
2420
+ if (options.progressToken !== void 0) {
2421
+ const activeCount = this.activeProgressTokens.get(options.progressToken);
2422
+ if (activeCount === 1) {
2423
+ this.activeProgressTokens.delete(options.progressToken);
2424
+ } else if (activeCount !== void 0) {
2425
+ this.activeProgressTokens.set(options.progressToken, activeCount - 1);
2426
+ }
2427
+ }
2428
+ }
2429
+ }
2430
+ async listResources(params = {}) {
2431
+ const messageLayer = this.getMessageLayerOrThrow();
2432
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2433
+ if (serverCapabilities.resources === void 0) {
2434
+ throw new Error("Server does not support resources");
2435
+ }
2436
+ const requestParams = params.cursor === void 0 ? void 0 : { cursor: params.cursor };
2437
+ const result = await messageLayer.sendRequest("resources/list", requestParams);
2438
+ if (!isResourcesListResult(result)) {
2439
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/list result");
2440
+ }
2441
+ return result;
2442
+ }
2443
+ async listResourceTemplates(params = {}) {
2444
+ const messageLayer = this.getMessageLayerOrThrow();
2445
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2446
+ if (serverCapabilities.resources === void 0) {
2447
+ throw new Error("Server does not support resources");
2448
+ }
2449
+ const requestParams = params.cursor === void 0 ? void 0 : { cursor: params.cursor };
2450
+ const result = await messageLayer.sendRequest("resources/templates/list", requestParams);
2451
+ if (!isResourceTemplatesListResult(result)) {
2452
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/templates/list result");
2453
+ }
2454
+ return result;
2455
+ }
2456
+ async readResource(params) {
2457
+ const messageLayer = this.getMessageLayerOrThrow();
2458
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2459
+ if (serverCapabilities.resources === void 0) {
2460
+ throw new Error("Server does not support resources");
2461
+ }
2462
+ const result = await messageLayer.sendRequest("resources/read", params);
2463
+ if (!isReadResourceResult(result)) {
2464
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/read result");
2465
+ }
2466
+ return result;
2467
+ }
2468
+ async subscribe(uri) {
2469
+ const messageLayer = this.getMessageLayerOrThrow();
2470
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2471
+ if (serverCapabilities.resources?.subscribe !== true) {
2472
+ throw new Error("Server does not support resource subscriptions");
2473
+ }
2474
+ await messageLayer.sendRequest("resources/subscribe", { uri });
2475
+ this.subscribedResourceUris.add(uri);
2476
+ }
2477
+ async unsubscribe(uri) {
2478
+ const messageLayer = this.getMessageLayerOrThrow();
2479
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2480
+ if (serverCapabilities.resources?.subscribe !== true) {
2481
+ throw new Error("Server does not support resource subscriptions");
2482
+ }
2483
+ await messageLayer.sendRequest("resources/unsubscribe", { uri });
2484
+ this.subscribedResourceUris.delete(uri);
2485
+ }
2486
+ async listPrompts(params = {}) {
2487
+ const messageLayer = this.getMessageLayerOrThrow();
2488
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2489
+ if (serverCapabilities.prompts === void 0) {
2490
+ throw new Error("Server does not support prompts");
2491
+ }
2492
+ const requestParams = params.cursor === void 0 ? void 0 : { cursor: params.cursor };
2493
+ return await messageLayer.sendRequest("prompts/list", requestParams);
2494
+ }
2495
+ async getPrompt(params) {
2496
+ const messageLayer = this.getMessageLayerOrThrow();
2497
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2498
+ if (serverCapabilities.prompts === void 0) {
2499
+ throw new Error("Server does not support prompts");
2500
+ }
2501
+ const result = await messageLayer.sendRequest("prompts/get", params);
2502
+ if (!isGetPromptResult(result)) {
2503
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid prompts/get result");
2504
+ }
2505
+ return result;
2506
+ }
2507
+ async complete(params) {
2508
+ const messageLayer = this.getMessageLayerOrThrow();
2509
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2510
+ if (serverCapabilities.completions === void 0) {
2511
+ throw new Error("Server does not support completions");
2512
+ }
2513
+ const result = await messageLayer.sendRequest("completion/complete", params);
2514
+ if (!isCompleteResult(result)) {
2515
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid completion/complete result");
2516
+ }
2517
+ return result;
2518
+ }
2519
+ async setLogLevel(level) {
2520
+ const messageLayer = this.getMessageLayerOrThrow();
2521
+ const serverCapabilities = this.getServerCapabilitiesOrThrow();
2522
+ if (serverCapabilities.logging === void 0) {
2523
+ throw new Error("Server does not support logging");
2524
+ }
2525
+ await messageLayer.sendRequest("logging/setLevel", { level });
2526
+ }
2527
+ async cancel(requestId, reason) {
2528
+ const messageLayer = this.getMessageLayerOrThrow();
2529
+ const params = { requestId };
2530
+ if (reason !== void 0) {
2531
+ params.reason = reason;
2532
+ }
2533
+ messageLayer.sendNotification("notifications/cancelled", params);
2534
+ }
2535
+ async sendRootsChanged() {
2536
+ const messageLayer = this.getMessageLayerOrThrow();
2537
+ if (this.currentClientCapabilities?.roots?.listChanged !== true) {
2538
+ throw new Error("Client did not advertise roots list changes");
2539
+ }
2540
+ messageLayer.sendNotification("notifications/roots/list_changed");
2541
+ }
2542
+ async ping() {
2543
+ const messageLayer = this.getMessageLayerOrThrow();
2544
+ await messageLayer.sendRequest("ping");
2545
+ }
2546
+ async close() {
2547
+ if (this.currentState === "closed") {
2548
+ return;
2549
+ }
2550
+ const closeError = new Error("MCP client closed");
2551
+ this.messageLayer?.dispose(closeError);
2552
+ this.transport?.dispose(closeError);
2553
+ this.messageLayer = null;
2554
+ this.transport = null;
2555
+ this.currentServerCapabilities = null;
2556
+ this.currentClientCapabilities = null;
2557
+ this.currentServerInfo = null;
2558
+ this.currentInstructions = void 0;
2559
+ this.subscribedResourceUris.clear();
2560
+ this.activeProgressTokens.clear();
2561
+ this.currentState = "closed";
2562
+ }
2563
+ };
2564
+ var ERROR_PARSE = -32700;
2565
+ var ERROR_INVALID_REQUEST = -32600;
2566
+ var ERROR_METHOD_NOT_FOUND = -32601;
2567
+ var ERROR_INVALID_PARAMS = -32602;
2568
+ var ERROR_INTERNAL = -32603;
2569
+ function createInMemoryTransportPair() {
2570
+ const clientToServer = new PassThrough();
2571
+ const serverToClient = new PassThrough();
2572
+ let disposed = false;
2573
+ let resolveClosed;
2574
+ const closed = new Promise((resolve) => {
2575
+ resolveClosed = resolve;
2576
+ });
2577
+ const resolveClosedOnce = (reason) => {
2578
+ if (resolveClosed === void 0) {
2579
+ return;
2580
+ }
2581
+ const currentResolve = resolveClosed;
2582
+ resolveClosed = void 0;
2583
+ currentResolve({ reason });
2584
+ };
2585
+ const dispose = (reason = new Error("In-memory transport disposed")) => {
2586
+ if (disposed) {
2587
+ return;
2588
+ }
2589
+ disposed = true;
2590
+ if (!clientToServer.destroyed && !clientToServer.writableEnded) {
2591
+ clientToServer.end();
2592
+ }
2593
+ if (!serverToClient.destroyed && !serverToClient.writableEnded) {
2594
+ serverToClient.end();
2595
+ }
2596
+ resolveClosedOnce(reason);
2597
+ };
2598
+ clientToServer.once("error", (error) => {
2599
+ dispose(error instanceof Error ? error : new Error(String(error)));
2600
+ });
2601
+ serverToClient.once("error", (error) => {
2602
+ dispose(error instanceof Error ? error : new Error(String(error)));
2603
+ });
2604
+ return {
2605
+ clientTransport: {
2606
+ readable: serverToClient,
2607
+ writable: clientToServer,
2608
+ closed,
2609
+ dispose
2610
+ },
2611
+ serverTransport: {
2612
+ readable: clientToServer,
2613
+ writable: serverToClient
2614
+ }
2615
+ };
2616
+ }
2617
+ var SdkTransportAdapter = class {
2618
+ readable;
2619
+ writable;
2620
+ closed;
2621
+ sdkTransport;
2622
+ readStream = new PassThrough();
2623
+ writeStream = new PassThrough();
2624
+ resolveClosed;
2625
+ disposed = false;
2626
+ constructor(sdkTransport) {
2627
+ this.sdkTransport = sdkTransport;
2628
+ this.readable = this.readStream;
2629
+ this.writable = this.writeStream;
2630
+ this.closed = new Promise((resolve) => {
2631
+ this.resolveClosed = resolve;
2632
+ });
2633
+ this.sdkTransport.onmessage = (message) => {
2634
+ this.readStream.write(serializeJsonRpcMessage(message));
2635
+ };
2636
+ this.sdkTransport.onclose = () => {
2637
+ this.dispose(new Error("SDK transport closed"));
2638
+ };
2639
+ this.sdkTransport.onerror = (error) => {
2640
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2641
+ };
2642
+ this.readStream.once("error", (error) => {
2643
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2644
+ });
2645
+ this.writeStream.once("error", (error) => {
2646
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2647
+ });
2648
+ this.consumeWrittenLines().catch((error) => {
2649
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2650
+ });
2651
+ this.sdkTransport.start().catch((error) => {
2652
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2653
+ });
2654
+ }
2655
+ dispose(reason = new Error("SDK transport adapter disposed")) {
2656
+ if (this.disposed) {
2657
+ return;
2658
+ }
2659
+ this.disposed = true;
2660
+ if (!this.writeStream.destroyed && !this.writeStream.writableEnded) {
2661
+ this.writeStream.end();
2662
+ }
2663
+ if (!this.readStream.destroyed && !this.readStream.writableEnded) {
2664
+ this.readStream.end();
2665
+ }
2666
+ if (this.resolveClosed !== void 0) {
2667
+ const resolveClosed = this.resolveClosed;
2668
+ this.resolveClosed = void 0;
2669
+ resolveClosed({ reason });
2670
+ }
2671
+ this.sdkTransport.close().catch(() => void 0);
2672
+ }
2673
+ async consumeWrittenLines() {
2674
+ for await (const line of readLines(this.writeStream)) {
2675
+ if (this.disposed || line.length === 0) {
2676
+ continue;
2677
+ }
2678
+ let parsedMessage;
2679
+ try {
2680
+ parsedMessage = JSON.parse(line);
2681
+ } catch {
2682
+ throw new Error(`Malformed JSON line: ${line}`);
2683
+ }
2684
+ if (typeof parsedMessage !== "object" || parsedMessage === null || Array.isArray(parsedMessage)) {
2685
+ throw new Error(`Malformed JSON line: ${line}`);
2686
+ }
2687
+ await this.sdkTransport.send(parsedMessage);
2688
+ }
2689
+ }
2690
+ };
2691
+ async function createSdkTestPair(server, createClient) {
2692
+ const { InMemoryTransport: InMemoryTransport2 } = await Promise.resolve().then(() => (init_inMemory(), inMemory_exports));
2693
+ const [clientSdkTransport, serverSdkTransport] = InMemoryTransport2.createLinkedPair();
2694
+ const clientTransport = new SdkTransportAdapter(clientSdkTransport);
2695
+ const serverPromise = server.connect(serverSdkTransport);
2696
+ const client = createClient();
2697
+ try {
2698
+ await client.connect(clientTransport);
2699
+ } catch (error) {
2700
+ clientTransport.dispose(new Error("SDK test pair setup failed"));
2701
+ await clientSdkTransport.close();
2702
+ await serverSdkTransport.close();
2703
+ await serverPromise;
2704
+ throw error;
2705
+ }
2706
+ const cleanup = async () => {
2707
+ await client.close();
2708
+ clientTransport.dispose(new Error("SDK test pair cleanup"));
2709
+ await clientSdkTransport.close();
2710
+ await serverSdkTransport.close();
2711
+ await serverPromise;
2712
+ };
2713
+ return { client, cleanup };
2714
+ }
2715
+ async function createTestPair(server, createClient) {
2716
+ const { clientTransport, serverTransport } = createInMemoryTransportPair();
2717
+ const serverPromise = server.connect(serverTransport);
2718
+ const client = createClient();
2719
+ try {
2720
+ await client.connect(clientTransport);
2721
+ } catch (error) {
2722
+ clientTransport.dispose(new Error("tiny-stdio-mcp-server test pair setup failed"));
2723
+ await serverPromise;
2724
+ throw error;
2725
+ }
2726
+ const cleanup = async () => {
2727
+ await client.close();
2728
+ clientTransport.dispose(new Error("tiny-stdio-mcp-server test pair cleanup"));
2729
+ await serverPromise;
2730
+ };
2731
+ return { client, cleanup };
2732
+ }
2733
+ function defaultStdioSpawn(command, args, options) {
2734
+ return spawn2(command, args, options);
2735
+ }
2736
+ function defaultHttpTransportFetch(input, init) {
2737
+ return fetch(input, init);
2738
+ }
2739
+ var StdioTransport = class _StdioTransport {
2740
+ readable;
2741
+ writable;
2742
+ closed;
2743
+ child;
2744
+ disposed = false;
2745
+ stderrOutput = "";
2746
+ static STDERR_MAX_LENGTH = 65536;
2747
+ constructor({
2748
+ command,
2749
+ args = [],
2750
+ cwd,
2751
+ env,
2752
+ spawn: spawnProcess = defaultStdioSpawn
2753
+ }) {
2754
+ this.child = spawnProcess(command, args, {
2755
+ cwd,
2756
+ env,
2757
+ stdio: ["pipe", "pipe", "pipe"]
2758
+ });
2759
+ const child = this.child;
2760
+ this.readable = child.stdout;
2761
+ this.writable = child.stdin;
2762
+ const stderrDecoder = new TextDecoder();
2763
+ child.stderr.on("data", (chunk) => {
2764
+ const decoded = chunk instanceof Uint8Array ? stderrDecoder.decode(chunk, { stream: true }) : `${stderrDecoder.decode()}${String(chunk)}`;
2765
+ this.appendStderrOutput(decoded);
2766
+ });
2767
+ child.stderr.once("end", () => {
2768
+ this.appendStderrOutput(stderrDecoder.decode());
2769
+ });
2770
+ this.closed = new Promise((resolve) => {
2771
+ let settled = false;
2772
+ const resolveClosed = (event) => {
2773
+ if (settled) {
2774
+ return;
2775
+ }
2776
+ settled = true;
2777
+ resolve(event);
2778
+ };
2779
+ child.once("exit", (code, signal) => {
2780
+ const closedEvent = {
2781
+ reason: new Error("Stdio transport process exited")
2782
+ };
2783
+ if (code !== null) {
2784
+ closedEvent.code = code;
2785
+ }
2786
+ if (signal !== null) {
2787
+ closedEvent.signal = signal;
2788
+ }
2789
+ resolveClosed(closedEvent);
2790
+ });
2791
+ child.once("error", (error) => {
2792
+ const closedEvent = {
2793
+ reason: error instanceof Error ? error : new Error(String(error))
2794
+ };
2795
+ if (child.exitCode !== null) {
2796
+ closedEvent.code = child.exitCode;
2797
+ }
2798
+ if (child.signalCode !== null) {
2799
+ closedEvent.signal = child.signalCode;
2800
+ }
2801
+ resolveClosed(closedEvent);
2802
+ });
2803
+ });
2804
+ }
2805
+ getStderrOutput() {
2806
+ return this.stderrOutput;
2807
+ }
2808
+ appendStderrOutput(chunk) {
2809
+ if (chunk.length === 0) {
2810
+ return;
2811
+ }
2812
+ this.stderrOutput += chunk;
2813
+ if (this.stderrOutput.length > _StdioTransport.STDERR_MAX_LENGTH) {
2814
+ this.stderrOutput = this.stderrOutput.slice(-_StdioTransport.STDERR_MAX_LENGTH);
2815
+ }
2816
+ }
2817
+ dispose(reason = new Error("Stdio transport disposed")) {
2818
+ void reason;
2819
+ if (this.disposed) {
2820
+ return;
2821
+ }
2822
+ this.disposed = true;
2823
+ if (!this.child.stdin.destroyed && !this.child.stdin.writableEnded) {
2824
+ this.child.stdin.end();
2825
+ }
2826
+ if (this.child.exitCode === null && this.child.signalCode === null && !this.child.killed) {
2827
+ this.child.kill("SIGTERM");
2828
+ }
2829
+ }
2830
+ };
2831
+ var HttpTransport = class {
2832
+ readable;
2833
+ writable;
2834
+ closed;
2835
+ url;
2836
+ headers;
2837
+ fetchImpl;
2838
+ readStream = new PassThrough();
2839
+ writeStream = new PassThrough();
2840
+ resolveClosed;
2841
+ sessionId;
2842
+ lastEventId;
2843
+ getSseStreamStarted = false;
2844
+ disposed = false;
2845
+ oauthProvider;
2846
+ oauthMetadataDiscovery;
2847
+ inFlightFetchAbortControllers = /* @__PURE__ */ new Set();
2848
+ openSseReaders = /* @__PURE__ */ new Set();
2849
+ constructor({
2850
+ url,
2851
+ headers = {},
2852
+ fetch: fetchImpl = defaultHttpTransportFetch,
2853
+ oauth,
2854
+ oauthDiscoveryCache
2855
+ }) {
2856
+ this.url = url;
2857
+ this.headers = headers;
2858
+ this.fetchImpl = fetchImpl;
2859
+ this.oauthProvider = oauth === void 0 ? void 0 : createOAuthClientProvider(oauth);
2860
+ this.oauthMetadataDiscovery = oauth === void 0 ? void 0 : new OAuthMetadataDiscovery({
2861
+ fetch: (input, init) => this.fetchWithAbort(input, init ?? {}),
2862
+ cache: oauthDiscoveryCache
2863
+ });
2864
+ this.readable = this.readStream;
2865
+ this.writable = this.writeStream;
2866
+ this.closed = new Promise((resolve) => {
2867
+ this.resolveClosed = resolve;
2868
+ });
2869
+ this.readStream.once("error", (error) => {
2870
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2871
+ });
2872
+ this.writeStream.once("error", (error) => {
2873
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2874
+ });
2875
+ this.consumeWrittenLines().catch((error) => {
2876
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2877
+ });
2878
+ }
2879
+ dispose(reason = new Error("HTTP transport disposed")) {
2880
+ if (this.disposed) {
2881
+ return;
2882
+ }
2883
+ this.disposed = true;
2884
+ this.abortInFlightFetches();
2885
+ this.cancelOpenSseReaders();
2886
+ if (!this.writeStream.destroyed && !this.writeStream.writableEnded) {
2887
+ this.writeStream.end();
2888
+ }
2889
+ if (!this.readStream.destroyed && !this.readStream.writableEnded) {
2890
+ this.readStream.end();
2891
+ }
2892
+ void this.closeWithSessionTermination(reason);
2893
+ }
2894
+ async closeWithSessionTermination(reason) {
2895
+ let closeReason = reason;
2896
+ if (this.sessionId !== void 0) {
2897
+ const sessionId = this.sessionId;
2898
+ this.sessionId = void 0;
2899
+ try {
2900
+ await this.sendSessionTerminationRequest(sessionId);
2901
+ } catch (error) {
2902
+ closeReason = error instanceof Error ? error : new Error(String(error));
2903
+ }
2904
+ }
2905
+ const resolveClosed = this.resolveClosed;
2906
+ this.resolveClosed = void 0;
2907
+ resolveClosed?.({ reason: closeReason });
2908
+ }
2909
+ abortInFlightFetches() {
2910
+ for (const abortController of this.inFlightFetchAbortControllers) {
2911
+ abortController.abort();
2912
+ }
2913
+ this.inFlightFetchAbortControllers.clear();
2914
+ }
2915
+ cancelOpenSseReaders() {
2916
+ for (const reader of this.openSseReaders) {
2917
+ void reader.cancel().catch(() => void 0);
2918
+ }
2919
+ this.openSseReaders.clear();
2920
+ }
2921
+ async fetchWithAbort(input, init) {
2922
+ const abortController = new AbortController();
2923
+ this.inFlightFetchAbortControllers.add(abortController);
2924
+ try {
2925
+ return await this.fetchImpl(input, {
2926
+ ...init,
2927
+ signal: abortController.signal
2928
+ });
2929
+ } finally {
2930
+ this.inFlightFetchAbortControllers.delete(abortController);
2931
+ }
2932
+ }
2933
+ async consumeWrittenLines() {
2934
+ for await (const line of readLines(this.writeStream)) {
2935
+ if (this.disposed || line.length === 0) {
2936
+ continue;
2937
+ }
2938
+ const hasSessionId = this.sessionId !== void 0;
2939
+ const response = await this.fetchWithOAuthRetry({
2940
+ method: "POST",
2941
+ createHeaders: () => this.createPostHeaders(),
2942
+ body: line
2943
+ });
2944
+ if (hasSessionId && response.status === 404) {
2945
+ this.sessionId = void 0;
2946
+ this.dispose(new Error("HTTP transport session expired (404 response)"));
2947
+ return;
2948
+ }
2949
+ await this.throwForPostHttpError(response);
2950
+ this.captureSessionId(response);
2951
+ this.maybeOpenGetSseStream();
2952
+ void this.forwardResponseMessages(response).catch((error) => {
2953
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
2954
+ });
2955
+ }
2956
+ }
2957
+ async createPostHeaders() {
2958
+ const headers = new Headers(this.headers);
2959
+ headers.set("Accept", "application/json, text/event-stream");
2960
+ headers.set("Content-Type", "application/json");
2961
+ if (this.sessionId !== void 0) {
2962
+ headers.set("Mcp-Session-Id", this.sessionId);
2963
+ headers.set("MCP-Protocol-Version", MCP_PROTOCOL_VERSION);
2964
+ }
2965
+ return this.authorizeRequestHeaders(headers);
2966
+ }
2967
+ async createGetHeaders() {
2968
+ const headers = new Headers(this.headers);
2969
+ headers.set("Accept", "text/event-stream");
2970
+ if (this.sessionId !== void 0) {
2971
+ headers.set("Mcp-Session-Id", this.sessionId);
2972
+ headers.set("MCP-Protocol-Version", MCP_PROTOCOL_VERSION);
2973
+ }
2974
+ if (this.lastEventId !== void 0) {
2975
+ headers.set("Last-Event-ID", this.lastEventId);
2976
+ }
2977
+ return this.authorizeRequestHeaders(headers);
2978
+ }
2979
+ async createDeleteHeaders(sessionId) {
2980
+ const headers = new Headers(this.headers);
2981
+ headers.set("Mcp-Session-Id", sessionId);
2982
+ headers.set("MCP-Protocol-Version", MCP_PROTOCOL_VERSION);
2983
+ return this.authorizeRequestHeaders(headers);
2984
+ }
2985
+ async authorizeRequestHeaders(headers) {
2986
+ await this.oauthProvider?.authorizeRequest?.({
2987
+ requestUrl: new URL(this.url),
2988
+ headers,
2989
+ fetch: this.fetchImpl
2990
+ });
2991
+ return headers;
2992
+ }
2993
+ captureSessionId(response) {
2994
+ const sessionId = response.headers.get("Mcp-Session-Id");
2995
+ if (sessionId === null || sessionId.length === 0) {
2996
+ return;
2997
+ }
2998
+ if (this.sessionId !== void 0 && this.sessionId !== sessionId) {
2999
+ throw new Error("HTTP transport response changed active session ID");
3000
+ }
3001
+ this.sessionId = sessionId;
3002
+ }
3003
+ maybeOpenGetSseStream() {
3004
+ if (this.disposed || this.sessionId === void 0 || this.getSseStreamStarted) {
3005
+ return;
3006
+ }
3007
+ this.getSseStreamStarted = true;
3008
+ this.consumeGetSseStream().catch((error) => {
3009
+ if (error instanceof HttpTransportGetSseNotSupportedError || this.disposed) {
3010
+ return;
3011
+ }
3012
+ this.dispose(error instanceof Error ? error : new Error(String(error)));
3013
+ });
3014
+ }
3015
+ async sendSessionTerminationRequest(sessionId) {
3016
+ const response = await this.fetchImpl(this.url, {
3017
+ method: "DELETE",
3018
+ headers: await this.createDeleteHeaders(sessionId)
3019
+ });
3020
+ if (response.status === 405 || response.ok) {
3021
+ return;
3022
+ }
3023
+ const responseBody = (await response.text()).trim();
3024
+ const statusDescriptor = `${response.status} ${response.statusText}`.trim();
3025
+ const message = responseBody.length === 0 ? `HTTP transport DELETE failed (${statusDescriptor})` : `HTTP transport DELETE failed (${statusDescriptor}): ${responseBody}`;
3026
+ throw new Error(message);
3027
+ }
3028
+ async consumeGetSseStream() {
3029
+ const response = await this.fetchWithOAuthRetry({
3030
+ method: "GET",
3031
+ createHeaders: () => this.createGetHeaders()
3032
+ });
3033
+ if (response.status === 405) {
3034
+ throw new HttpTransportGetSseNotSupportedError();
3035
+ }
3036
+ if (response.status === 404) {
3037
+ this.sessionId = void 0;
3038
+ throw new Error("HTTP transport session expired (GET 404 response)");
3039
+ }
3040
+ if (!response.ok) {
3041
+ const responseBody = (await response.text()).trim();
3042
+ const statusDescriptor = `${response.status} ${response.statusText}`.trim();
3043
+ const message = responseBody.length === 0 ? `HTTP transport GET failed (${statusDescriptor})` : `HTTP transport GET failed (${statusDescriptor}): ${responseBody}`;
3044
+ throw new Error(message);
3045
+ }
3046
+ const contentType = response.headers.get("Content-Type");
3047
+ if (contentType === null) {
3048
+ return;
3049
+ }
3050
+ if (contentType.toLowerCase().includes("text/event-stream")) {
3051
+ await this.forwardSseResponseMessages(response);
3052
+ this.getSseStreamStarted = false;
3053
+ if (!this.disposed && this.sessionId !== void 0 && this.lastEventId !== void 0) {
3054
+ this.maybeOpenGetSseStream();
3055
+ }
3056
+ return;
3057
+ }
3058
+ return;
3059
+ }
3060
+ async throwForPostHttpError(response) {
3061
+ if (response.status < 400) {
3062
+ return;
3063
+ }
3064
+ const responseBody = (await response.text()).trim();
3065
+ const statusDescriptor = `${response.status} ${response.statusText}`.trim();
3066
+ const message = responseBody.length === 0 ? `HTTP transport POST failed (${statusDescriptor})` : `HTTP transport POST failed (${statusDescriptor}): ${responseBody}`;
3067
+ throw new Error(message);
3068
+ }
3069
+ async maybeHandleUnauthorizedResponse(response) {
3070
+ if (response.status !== 401 || this.oauthProvider === void 0) {
3071
+ return false;
3072
+ }
3073
+ const discoveryClient = this.oauthMetadataDiscovery;
3074
+ if (discoveryClient === void 0) {
3075
+ return false;
3076
+ }
3077
+ const challenge = parseBearerWwwAuthenticateHeader(response.headers.get("WWW-Authenticate"));
3078
+ const resourceMetadataUrl = challenge?.params.resource_metadata;
3079
+ const discovery = await discoveryClient.discover(this.url, {
3080
+ resourceMetadataUrl
3081
+ });
3082
+ const result = await this.oauthProvider.handleUnauthorized({
3083
+ requestUrl: new URL(this.url),
3084
+ response: response.clone(),
3085
+ challenge,
3086
+ discovery,
3087
+ fetch: this.fetchImpl
3088
+ });
3089
+ if (result.action === "retry") {
3090
+ return true;
3091
+ }
3092
+ if (result.error !== void 0) {
3093
+ throw result.error;
3094
+ }
3095
+ return false;
3096
+ }
3097
+ async forwardResponseMessages(response) {
3098
+ if (response.status === 202) {
3099
+ return;
3100
+ }
3101
+ const contentType = response.headers.get("Content-Type");
3102
+ if (contentType === null) {
3103
+ return;
3104
+ }
3105
+ const normalizedContentType = contentType.toLowerCase();
3106
+ if (normalizedContentType.includes("text/event-stream")) {
3107
+ await this.forwardSseResponseMessages(response);
3108
+ return;
3109
+ }
3110
+ if (normalizedContentType.includes("application/json")) {
3111
+ await this.forwardJsonResponseMessage(response);
3112
+ return;
3113
+ }
3114
+ throw new Error("HTTP transport POST returned an unsupported response content type");
3115
+ }
3116
+ async forwardSseResponseMessages(response) {
3117
+ if (response.body === null) {
3118
+ return;
3119
+ }
3120
+ const parser = new SseParser();
3121
+ const decoder = new TextDecoder();
3122
+ const reader = response.body.getReader();
3123
+ this.openSseReaders.add(reader);
3124
+ try {
3125
+ while (true) {
3126
+ const { done, value } = await reader.read();
3127
+ if (done) {
3128
+ break;
3129
+ }
3130
+ if (value === void 0) {
3131
+ continue;
3132
+ }
3133
+ const messages = parser.push(decoder.decode(value, { stream: true }));
3134
+ this.writeSseMessages(messages);
3135
+ this.lastEventId = parser.lastEventId;
3136
+ }
3137
+ const trailingChunk = decoder.decode();
3138
+ if (trailingChunk.length > 0) {
3139
+ this.writeSseMessages(parser.push(trailingChunk));
3140
+ this.lastEventId = parser.lastEventId;
3141
+ }
3142
+ this.writeSseMessages(parser.flush());
3143
+ this.lastEventId = parser.lastEventId;
3144
+ } finally {
3145
+ this.openSseReaders.delete(reader);
3146
+ reader.releaseLock();
3147
+ }
3148
+ }
3149
+ async forwardJsonResponseMessage(response) {
3150
+ const payload = await response.text();
3151
+ if (payload.length === 0) {
3152
+ return;
3153
+ }
3154
+ const parsedPayload = JSON.parse(payload);
3155
+ this.writeReadableLine(JSON.stringify(parsedPayload));
3156
+ }
3157
+ writeSseMessages(messages) {
3158
+ for (const message of messages) {
3159
+ this.writeReadableLine(message.data);
3160
+ }
3161
+ }
3162
+ writeReadableLine(line) {
3163
+ if (this.disposed || this.readStream.destroyed || this.readStream.writableEnded) {
3164
+ return;
3165
+ }
3166
+ this.readStream.write(`${line}
3167
+ `);
3168
+ }
3169
+ async fetchWithOAuthRetry(input) {
3170
+ const request = async () => this.fetchWithAbort(this.url, {
3171
+ method: input.method,
3172
+ headers: await input.createHeaders(),
3173
+ body: input.body
3174
+ });
3175
+ let response = await request();
3176
+ if (await this.maybeHandleUnauthorizedResponse(response)) {
3177
+ response = await request();
3178
+ }
3179
+ const oauthError = this.oauthProvider === void 0 ? null : this.readOAuthChallengeError(response);
3180
+ if (oauthError !== null) {
3181
+ throw oauthError;
3182
+ }
3183
+ return response;
3184
+ }
3185
+ readOAuthChallengeError(response) {
3186
+ if (response.status !== 401 && response.status !== 403) {
3187
+ return null;
3188
+ }
3189
+ const challenge = parseBearerWwwAuthenticateHeader(response.headers.get("WWW-Authenticate"));
3190
+ const error = challenge?.params.error;
3191
+ if (error === void 0 || error.length === 0) {
3192
+ return null;
3193
+ }
3194
+ return new OAuthError(
3195
+ {
3196
+ error,
3197
+ error_description: challenge?.params.error_description,
3198
+ error_uri: challenge?.params.error_uri
3199
+ },
3200
+ response.status
3201
+ );
3202
+ }
3203
+ };
3204
+ var HttpTransportGetSseNotSupportedError = class extends Error {
3205
+ constructor() {
3206
+ super("HTTP transport server does not support GET SSE streams");
3207
+ }
3208
+ };
3209
+ var McpError = class extends Error {
3210
+ code;
3211
+ constructor(code, message, data) {
3212
+ super(message);
3213
+ this.name = "McpError";
3214
+ this.code = code;
3215
+ if (data !== void 0) {
3216
+ this.data = data;
3217
+ }
3218
+ }
3219
+ };
3220
+ function serializeJsonRpcMessage(message) {
3221
+ return `${JSON.stringify(message)}
3222
+ `;
3223
+ }
3224
+ function normalizeLine(line) {
3225
+ return line.endsWith("\r") ? line.slice(0, -1) : line;
3226
+ }
3227
+ async function* readLines(stream) {
3228
+ let buffer = "";
3229
+ const decoder = new TextDecoder();
3230
+ for await (const chunk of stream) {
3231
+ buffer += chunk instanceof Uint8Array ? decoder.decode(chunk, { stream: true }) : decoder.decode() + String(chunk);
3232
+ while (true) {
3233
+ const newlineIndex = buffer.indexOf("\n");
3234
+ if (newlineIndex === -1) {
3235
+ break;
3236
+ }
3237
+ const line = buffer.slice(0, newlineIndex);
3238
+ buffer = buffer.slice(newlineIndex + 1);
3239
+ yield normalizeLine(line);
3240
+ }
3241
+ }
3242
+ buffer += decoder.decode();
3243
+ if (buffer.length > 0) {
3244
+ yield normalizeLine(buffer);
3245
+ }
3246
+ }
3247
+ var SseParser = class {
3248
+ buffer = "";
3249
+ eventType;
3250
+ dataLines = [];
3251
+ eventId = "";
3252
+ hasEventId = false;
3253
+ _lastEventId;
3254
+ get lastEventId() {
3255
+ return this._lastEventId;
3256
+ }
3257
+ push(chunk) {
3258
+ if (chunk.length === 0) {
3259
+ return [];
3260
+ }
3261
+ this.buffer += chunk;
3262
+ const messages = [];
3263
+ while (true) {
3264
+ const newlineIndex = this.buffer.indexOf("\n");
3265
+ if (newlineIndex === -1) {
3266
+ break;
3267
+ }
3268
+ const line = normalizeLine(this.buffer.slice(0, newlineIndex));
3269
+ this.buffer = this.buffer.slice(newlineIndex + 1);
3270
+ this.consumeLine(line, messages);
3271
+ }
3272
+ return messages;
3273
+ }
3274
+ flush() {
3275
+ const messages = [];
3276
+ if (this.buffer.length > 0) {
3277
+ this.consumeLine(normalizeLine(this.buffer), messages);
3278
+ this.buffer = "";
3279
+ }
3280
+ this.emitEvent(messages);
3281
+ return messages;
3282
+ }
3283
+ consumeLine(line, messages) {
3284
+ if (line.length === 0) {
3285
+ this.emitEvent(messages);
3286
+ return;
3287
+ }
3288
+ if (line.startsWith(":")) {
3289
+ return;
3290
+ }
3291
+ const separatorIndex = line.indexOf(":");
3292
+ const field = separatorIndex === -1 ? line : line.slice(0, separatorIndex);
3293
+ const rawValue = separatorIndex === -1 ? "" : line.slice(separatorIndex + 1);
3294
+ const value = rawValue.startsWith(" ") ? rawValue.slice(1) : rawValue;
3295
+ if (field === "event") {
3296
+ this.eventType = value;
3297
+ return;
3298
+ }
3299
+ if (field === "data") {
3300
+ this.dataLines.push(value);
3301
+ return;
3302
+ }
3303
+ if (field === "id") {
3304
+ if (value.includes("\0")) {
3305
+ return;
3306
+ }
3307
+ this.eventId = value;
3308
+ this.hasEventId = true;
3309
+ }
3310
+ }
3311
+ emitEvent(messages) {
3312
+ const eventType = this.eventType ?? "message";
3313
+ if (this.hasEventId) {
3314
+ this._lastEventId = this.eventId;
3315
+ }
3316
+ if (this.dataLines.length === 0 || eventType !== "message") {
3317
+ this.resetEvent();
3318
+ return;
3319
+ }
3320
+ const message = {
3321
+ data: this.dataLines.join("\n")
3322
+ };
3323
+ if (this.hasEventId) {
3324
+ message.id = this.eventId;
3325
+ }
3326
+ messages.push(message);
3327
+ this.resetEvent();
3328
+ }
3329
+ resetEvent() {
3330
+ this.eventType = void 0;
3331
+ this.dataLines = [];
3332
+ this.eventId = "";
3333
+ this.hasEventId = false;
3334
+ }
3335
+ };
3336
+ var JsonRpcMessageLayer = class {
3337
+ requestTimeoutMs;
3338
+ input;
3339
+ output;
3340
+ inputClosedReason;
3341
+ nextRequestId = 1;
3342
+ disposedError;
3343
+ pendingRequests = /* @__PURE__ */ new Map();
3344
+ activeIncomingRequests = /* @__PURE__ */ new Map();
3345
+ requestHandlers = /* @__PURE__ */ new Map();
3346
+ notificationHandlers = /* @__PURE__ */ new Map();
3347
+ constructor(input, output, requestTimeoutMs = 3e4, inputClosedReason) {
3348
+ if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs < 0) {
3349
+ throw new Error("requestTimeoutMs must be a non-negative finite number");
3350
+ }
3351
+ this.input = input;
3352
+ this.output = output;
3353
+ this.inputClosedReason = inputClosedReason;
3354
+ this.requestTimeoutMs = requestTimeoutMs;
3355
+ this.consumeInput().catch(() => void 0);
3356
+ }
3357
+ sendNotification(method, params) {
3358
+ if (this.disposedError !== void 0) {
3359
+ throw this.disposedError;
3360
+ }
3361
+ const message = {
3362
+ jsonrpc: "2.0",
3363
+ method
3364
+ };
3365
+ if (params !== void 0) {
3366
+ message.params = params;
3367
+ }
3368
+ this.output.write(serializeJsonRpcMessage(message));
3369
+ }
3370
+ onRequest(method, handler) {
3371
+ this.requestHandlers.set(method, handler);
3372
+ }
3373
+ onNotification(method, handler) {
3374
+ this.notificationHandlers.set(method, handler);
3375
+ }
3376
+ sendRequest(method, params, options = {}) {
3377
+ if (this.disposedError !== void 0) {
3378
+ throw this.disposedError;
3379
+ }
3380
+ const id = this.nextRequestId;
3381
+ this.nextRequestId += 1;
3382
+ const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
3383
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
3384
+ throw new Error("timeoutMs must be a non-negative finite number");
3385
+ }
3386
+ if (options.onRequestId !== void 0) {
3387
+ options.onRequestId(id);
3388
+ }
3389
+ const message = {
3390
+ jsonrpc: "2.0",
3391
+ id,
3392
+ method
3393
+ };
3394
+ if (params !== void 0) {
3395
+ message.params = params;
3396
+ }
3397
+ return new Promise((resolve, reject) => {
3398
+ const timeout = setTimeout(() => {
3399
+ this.pendingRequests.delete(id);
3400
+ options.onTimeout?.(id);
3401
+ reject(new Error(`JSON-RPC request "${method}" timed out after ${timeoutMs}ms`));
3402
+ }, timeoutMs);
3403
+ this.pendingRequests.set(id, { resolve, reject, timeout });
3404
+ try {
3405
+ this.output.write(serializeJsonRpcMessage(message));
3406
+ } catch (error) {
3407
+ clearTimeout(timeout);
3408
+ this.pendingRequests.delete(id);
3409
+ reject(error);
3410
+ }
3411
+ });
3412
+ }
3413
+ cancelRequest(requestId, reason) {
3414
+ const pending = this.pendingRequests.get(requestId);
3415
+ if (pending === void 0) {
3416
+ return false;
3417
+ }
3418
+ this.pendingRequests.delete(requestId);
3419
+ clearTimeout(pending.timeout);
3420
+ pending.reject(reason);
3421
+ return true;
3422
+ }
3423
+ dispose(reason = new Error("JSON-RPC message layer disposed")) {
3424
+ if (this.disposedError !== void 0) {
3425
+ return;
3426
+ }
3427
+ this.disposedError = reason;
3428
+ for (const pending of this.pendingRequests.values()) {
3429
+ clearTimeout(pending.timeout);
3430
+ pending.reject(reason);
3431
+ }
3432
+ this.pendingRequests.clear();
3433
+ this.activeIncomingRequests.clear();
3434
+ }
3435
+ async consumeInput() {
3436
+ try {
3437
+ for await (const line of readLines(this.input)) {
3438
+ if (this.disposedError !== void 0) {
3439
+ break;
3440
+ }
3441
+ if (line.length === 0) {
3442
+ continue;
3443
+ }
3444
+ let parsedLine;
3445
+ try {
3446
+ parsedLine = JSON.parse(line);
3447
+ } catch {
3448
+ await this.processParsedMessage({
3449
+ type: "invalid",
3450
+ id: null,
3451
+ error: parseError()
3452
+ });
3453
+ continue;
3454
+ }
3455
+ if (Array.isArray(parsedLine)) {
3456
+ for (const message of parsedLine) {
3457
+ if (this.disposedError !== void 0) {
3458
+ break;
3459
+ }
3460
+ await this.processParsedMessage(parseJsonRpcPayload(message));
3461
+ }
3462
+ continue;
3463
+ }
3464
+ await this.processParsedMessage(parseJsonRpcPayload(parsedLine));
3465
+ }
3466
+ } catch (error) {
3467
+ if (this.disposedError === void 0) {
3468
+ this.dispose(
3469
+ error instanceof Error ? error : new Error(`JSON-RPC input stream failed: ${String(error)}`)
3470
+ );
3471
+ }
3472
+ return;
3473
+ }
3474
+ if (this.disposedError === void 0) {
3475
+ const streamClosedReason = await this.resolveInputStreamClosedReason();
3476
+ if (this.disposedError === void 0) {
3477
+ this.dispose(streamClosedReason);
3478
+ }
3479
+ }
3480
+ }
3481
+ async resolveInputStreamClosedReason() {
3482
+ const streamClosedError = new Error("JSON-RPC input stream closed");
3483
+ if (this.inputClosedReason === void 0) {
3484
+ return streamClosedError;
3485
+ }
3486
+ try {
3487
+ return await Promise.race([
3488
+ this.inputClosedReason,
3489
+ new Promise((resolve) => {
3490
+ setTimeout(() => {
3491
+ resolve(streamClosedError);
3492
+ }, 50);
3493
+ })
3494
+ ]);
3495
+ } catch {
3496
+ return streamClosedError;
3497
+ }
3498
+ }
3499
+ async processParsedMessage(parsed) {
3500
+ if (parsed.type === "request") {
3501
+ const handler = this.requestHandlers.get(parsed.message.method);
3502
+ if (handler === void 0) {
3503
+ this.output.write(
3504
+ serializeJsonRpcMessage({
3505
+ jsonrpc: "2.0",
3506
+ id: parsed.message.id,
3507
+ error: {
3508
+ code: ERROR_METHOD_NOT_FOUND,
3509
+ message: `Method not found: ${parsed.message.method}`
3510
+ }
3511
+ })
3512
+ );
3513
+ return;
3514
+ }
3515
+ this.handleIncomingRequest(parsed.message, handler);
3516
+ return;
3517
+ }
3518
+ if (parsed.type === "notification") {
3519
+ if (parsed.message.method === "notifications/cancelled") {
3520
+ this.handleCancellationNotification(parsed.message.params);
3521
+ }
3522
+ const handler = this.notificationHandlers.get(parsed.message.method);
3523
+ if (handler === void 0) {
3524
+ return;
3525
+ }
3526
+ try {
3527
+ await handler(parsed.message.params, {
3528
+ method: parsed.message.method
3529
+ });
3530
+ } catch {
3531
+ return;
3532
+ }
3533
+ return;
3534
+ }
3535
+ if (parsed.type === "invalid") {
3536
+ const errorResponse = {
3537
+ jsonrpc: "2.0",
3538
+ id: parsed.id,
3539
+ error: {
3540
+ code: parsed.error.code,
3541
+ message: parsed.error.message
3542
+ }
3543
+ };
3544
+ if (parsed.error.data !== void 0) {
3545
+ errorResponse.error.data = parsed.error.data;
3546
+ }
3547
+ this.output.write(`${JSON.stringify(errorResponse)}
3548
+ `);
3549
+ return;
3550
+ }
3551
+ if (parsed.type !== "response") {
3552
+ return;
3553
+ }
3554
+ const pending = this.pendingRequests.get(parsed.message.id);
3555
+ if (pending === void 0) {
3556
+ return;
3557
+ }
3558
+ this.pendingRequests.delete(parsed.message.id);
3559
+ clearTimeout(pending.timeout);
3560
+ if ("result" in parsed.message) {
3561
+ pending.resolve(parsed.message.result);
3562
+ return;
3563
+ }
3564
+ pending.reject(
3565
+ new McpError(
3566
+ parsed.message.error.code,
3567
+ parsed.message.error.message,
3568
+ parsed.message.error.data
3569
+ )
3570
+ );
3571
+ }
3572
+ handleIncomingRequest(message, handler) {
3573
+ const activeRequest = {
3574
+ cancelled: false
3575
+ };
3576
+ this.activeIncomingRequests.set(message.id, activeRequest);
3577
+ void (async () => {
3578
+ try {
3579
+ const result = await handler(message.params, {
3580
+ id: message.id,
3581
+ method: message.method
3582
+ });
3583
+ if (this.disposedError !== void 0 || activeRequest.cancelled) {
3584
+ return;
3585
+ }
3586
+ this.output.write(
3587
+ serializeJsonRpcMessage({
3588
+ jsonrpc: "2.0",
3589
+ id: message.id,
3590
+ result
3591
+ })
3592
+ );
3593
+ } catch (error) {
3594
+ if (this.disposedError !== void 0 || activeRequest.cancelled) {
3595
+ return;
3596
+ }
3597
+ const errorMessage = error instanceof Error ? error.message : String(error);
3598
+ this.output.write(
3599
+ serializeJsonRpcMessage({
3600
+ jsonrpc: "2.0",
3601
+ id: message.id,
3602
+ error: {
3603
+ code: ERROR_INTERNAL,
3604
+ message: errorMessage
3605
+ }
3606
+ })
3607
+ );
3608
+ } finally {
3609
+ const inFlightRequest = this.activeIncomingRequests.get(message.id);
3610
+ if (inFlightRequest === activeRequest) {
3611
+ this.activeIncomingRequests.delete(message.id);
3612
+ }
3613
+ }
3614
+ })();
3615
+ }
3616
+ handleCancellationNotification(params) {
3617
+ if (!isObjectRecord5(params)) {
3618
+ return;
3619
+ }
3620
+ const requestId = params.requestId;
3621
+ if (!isRequestId(requestId)) {
3622
+ return;
3623
+ }
3624
+ const activeRequest = this.activeIncomingRequests.get(requestId);
3625
+ if (activeRequest === void 0) {
3626
+ return;
3627
+ }
3628
+ activeRequest.cancelled = true;
3629
+ this.activeIncomingRequests.delete(requestId);
3630
+ }
3631
+ };
3632
+ function isObjectRecord5(value) {
3633
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3634
+ }
3635
+ function isInitializeResult(value) {
3636
+ if (!isObjectRecord5(value) || typeof value.protocolVersion !== "string") {
3637
+ return false;
3638
+ }
3639
+ if (!isServerCapabilities(value.capabilities)) {
3640
+ return false;
3641
+ }
3642
+ if (!isObjectRecord5(value.serverInfo) || typeof value.serverInfo.name !== "string" || value.serverInfo.name.length === 0 || typeof value.serverInfo.version !== "string" || value.serverInfo.version.length === 0) {
3643
+ return false;
3644
+ }
3645
+ return value.instructions === void 0 || typeof value.instructions === "string";
3646
+ }
3647
+ function isServerCapabilities(value) {
3648
+ if (!isObjectRecord5(value)) {
3649
+ return false;
3650
+ }
3651
+ for (const capability of ["prompts", "resources", "tools", "logging", "completions", "experimental"]) {
3652
+ if (value[capability] !== void 0 && !isObjectRecord5(value[capability])) {
3653
+ return false;
3654
+ }
3655
+ }
3656
+ return true;
3657
+ }
3658
+ function isCallToolResult(value) {
3659
+ if (!isObjectRecord5(value) || !Array.isArray(value.content)) {
3660
+ return false;
3661
+ }
3662
+ if (value.structuredContent !== void 0 && !isObjectRecord5(value.structuredContent)) {
3663
+ return false;
3664
+ }
3665
+ if (value.isError !== void 0 && typeof value.isError !== "boolean") {
3666
+ return false;
3667
+ }
3668
+ return value.content.every(isContentItem);
3669
+ }
3670
+ function isToolsListResult(value) {
3671
+ return isObjectRecord5(value) && Array.isArray(value.tools) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
3672
+ }
3673
+ function isResourcesListResult(value) {
3674
+ return isObjectRecord5(value) && Array.isArray(value.resources) && value.resources.every(isResource) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
3675
+ }
3676
+ function isResourceTemplatesListResult(value) {
3677
+ return isObjectRecord5(value) && Array.isArray(value.resourceTemplates) && value.resourceTemplates.every(isResourceTemplate) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
3678
+ }
3679
+ function isReadResourceResult(value) {
3680
+ return isObjectRecord5(value) && Array.isArray(value.contents) && value.contents.every(isResourceContents);
3681
+ }
3682
+ function isGetPromptResult(value) {
3683
+ return isObjectRecord5(value) && (value.description === void 0 || typeof value.description === "string") && Array.isArray(value.messages) && value.messages.every(isPromptMessage);
3684
+ }
3685
+ function isCompleteResult(value) {
3686
+ return isObjectRecord5(value) && isObjectRecord5(value.completion) && Array.isArray(value.completion.values) && value.completion.values.every((candidate) => typeof candidate === "string") && (value.completion.hasMore === void 0 || typeof value.completion.hasMore === "boolean") && (value.completion.total === void 0 || typeof value.completion.total === "number");
3687
+ }
3688
+ function isResource(value) {
3689
+ return isObjectRecord5(value) && typeof value.uri === "string" && typeof value.name === "string" && (value.description === void 0 || typeof value.description === "string") && (value.mimeType === void 0 || typeof value.mimeType === "string") && (value.size === void 0 || typeof value.size === "number");
3690
+ }
3691
+ function isResourceTemplate(value) {
3692
+ return isObjectRecord5(value) && typeof value.uriTemplate === "string" && typeof value.name === "string" && (value.description === void 0 || typeof value.description === "string") && (value.mimeType === void 0 || typeof value.mimeType === "string");
3693
+ }
3694
+ function isResourceContents(value) {
3695
+ if (!isObjectRecord5(value) || typeof value.uri !== "string") {
3696
+ return false;
3697
+ }
3698
+ if (value.mimeType !== void 0 && typeof value.mimeType !== "string") {
3699
+ return false;
3700
+ }
3701
+ const hasText = value.text !== void 0;
3702
+ const hasBlob = value.blob !== void 0;
3703
+ if (!hasText && !hasBlob) {
3704
+ return false;
3705
+ }
3706
+ return (!hasText || typeof value.text === "string") && (!hasBlob || typeof value.blob === "string");
3707
+ }
3708
+ function isPromptMessage(value) {
3709
+ return isObjectRecord5(value) && (value.role === "user" || value.role === "assistant") && isContentItem(value.content);
3710
+ }
3711
+ function isContentItem(value) {
3712
+ if (!isObjectRecord5(value)) {
3713
+ return false;
3714
+ }
3715
+ if (value.type === "text") {
3716
+ return typeof value.text === "string";
3717
+ }
3718
+ if (value.type === "image" || value.type === "audio") {
3719
+ return typeof value.data === "string" && typeof value.mimeType === "string";
3720
+ }
3721
+ if (value.type !== "resource" || !isObjectRecord5(value.resource)) {
3722
+ return false;
3723
+ }
3724
+ return isResourceContents(value.resource);
3725
+ }
3726
+ function hasOwn(value, property) {
3727
+ return Object.prototype.hasOwnProperty.call(value, property);
3728
+ }
3729
+ function isRequestId(value) {
3730
+ return typeof value === "string" || typeof value === "number";
3731
+ }
3732
+ function isLogLevel(value) {
3733
+ return value === "debug" || value === "info" || value === "notice" || value === "warning" || value === "error" || value === "critical" || value === "alert" || value === "emergency";
3734
+ }
3735
+ function toRequestId(value) {
3736
+ return isRequestId(value) ? value : null;
3737
+ }
3738
+ function parseError() {
3739
+ return new McpError(ERROR_PARSE, "Parse error");
3740
+ }
3741
+ function invalidRequest() {
3742
+ return new McpError(ERROR_INVALID_REQUEST, "Invalid Request");
3743
+ }
3744
+ function isJsonRpcErrorObject(value) {
3745
+ if (!isObjectRecord5(value)) {
3746
+ return false;
3747
+ }
3748
+ if (typeof value.code !== "number" || typeof value.message !== "string") {
3749
+ return false;
3750
+ }
3751
+ return value.data === void 0 || hasOwn(value, "data");
3752
+ }
3753
+ function parseJsonRpcPayload(parsed) {
3754
+ if (!isObjectRecord5(parsed)) {
3755
+ return {
3756
+ type: "invalid",
3757
+ id: null,
3758
+ error: invalidRequest()
3759
+ };
3760
+ }
3761
+ const id = toRequestId(parsed.id);
3762
+ if (parsed.jsonrpc !== "2.0") {
3763
+ return {
3764
+ type: "invalid",
3765
+ id,
3766
+ error: invalidRequest()
3767
+ };
3768
+ }
3769
+ const hasMethod = hasOwn(parsed, "method");
3770
+ const hasId = hasOwn(parsed, "id");
3771
+ if (hasMethod) {
3772
+ if (typeof parsed.method !== "string") {
3773
+ return {
3774
+ type: "invalid",
3775
+ id,
3776
+ error: invalidRequest()
3777
+ };
3778
+ }
3779
+ if (hasId) {
3780
+ if (!isRequestId(parsed.id)) {
3781
+ return {
3782
+ type: "invalid",
3783
+ id: null,
3784
+ error: invalidRequest()
3785
+ };
3786
+ }
3787
+ const request = {
3788
+ jsonrpc: "2.0",
3789
+ id: parsed.id,
3790
+ method: parsed.method
3791
+ };
3792
+ if (hasOwn(parsed, "params")) {
3793
+ request.params = parsed.params;
3794
+ }
3795
+ return {
3796
+ type: "request",
3797
+ message: request
3798
+ };
3799
+ }
3800
+ const notification = {
3801
+ jsonrpc: "2.0",
3802
+ method: parsed.method
3803
+ };
3804
+ if (hasOwn(parsed, "params")) {
3805
+ notification.params = parsed.params;
3806
+ }
3807
+ return {
3808
+ type: "notification",
3809
+ message: notification
3810
+ };
3811
+ }
3812
+ if (!hasId || !isRequestId(parsed.id)) {
3813
+ return {
3814
+ type: "invalid",
3815
+ id,
3816
+ error: invalidRequest()
3817
+ };
3818
+ }
3819
+ const hasResult = hasOwn(parsed, "result");
3820
+ const hasError = hasOwn(parsed, "error");
3821
+ if (hasResult === hasError) {
3822
+ return {
3823
+ type: "invalid",
3824
+ id: parsed.id,
3825
+ error: invalidRequest()
3826
+ };
3827
+ }
3828
+ if (hasResult) {
3829
+ return {
3830
+ type: "response",
3831
+ message: {
3832
+ jsonrpc: "2.0",
3833
+ id: parsed.id,
3834
+ result: parsed.result
3835
+ }
3836
+ };
3837
+ }
3838
+ if (!isJsonRpcErrorObject(parsed.error)) {
3839
+ return {
3840
+ type: "invalid",
3841
+ id: parsed.id,
3842
+ error: invalidRequest()
3843
+ };
3844
+ }
3845
+ return {
3846
+ type: "response",
3847
+ message: {
3848
+ jsonrpc: "2.0",
3849
+ id: parsed.id,
3850
+ error: parsed.error
3851
+ }
3852
+ };
3853
+ }
3854
+ export {
3855
+ ERROR_INTERNAL,
3856
+ ERROR_INVALID_PARAMS,
3857
+ ERROR_INVALID_REQUEST,
3858
+ ERROR_METHOD_NOT_FOUND,
3859
+ ERROR_PARSE,
3860
+ HttpTransport,
3861
+ JsonRpcMessageLayer,
3862
+ McpClient,
3863
+ McpError,
3864
+ OAuthMetadataDiscovery,
3865
+ StdioTransport,
3866
+ createInMemoryTransportPair,
3867
+ createSdkTestPair,
3868
+ createTestPair,
3869
+ discoverOAuthMetadata
3870
+ };