@introspection-ai/recipes 0.19.2 → 0.20.0

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 (116) hide show
  1. package/dist/agents.d.ts +17 -1
  2. package/dist/agents.d.ts.map +1 -1
  3. package/dist/agents.js +15 -1
  4. package/dist/agents.js.map +1 -1
  5. package/dist/child-agent.d.ts +3 -1
  6. package/dist/child-agent.d.ts.map +1 -1
  7. package/dist/child-agent.js +1 -0
  8. package/dist/child-agent.js.map +1 -1
  9. package/dist/mcp-chunks/{auth-command-3K7V3VCW.js → auth-command-IQ4J332A.js} +26 -38
  10. package/dist/mcp-chunks/call-arguments-MCCBPJMY.js +15 -0
  11. package/dist/mcp-chunks/{call-command-OFPHPFM5.js → call-command-WPQ3MDOE.js} +74 -40
  12. package/dist/mcp-chunks/{chunk-LNSUME65.js → chunk-24FKKIXI.js} +29 -13
  13. package/dist/mcp-chunks/{chunk-HTZ2URXW.js → chunk-2CTVPSHF.js} +3 -3
  14. package/dist/mcp-chunks/{chunk-NCXEJ35U.js → chunk-3FB4ZJ4Z.js} +4 -4
  15. package/dist/mcp-chunks/{chunk-P3RN22HQ.js → chunk-3MIFROM7.js} +3 -2
  16. package/dist/mcp-chunks/{chunk-GFYTST6N.js → chunk-54UGGTOX.js} +1 -1
  17. package/dist/mcp-chunks/{chunk-L4VKBFYI.js → chunk-5HQYKAE7.js} +101 -16
  18. package/dist/mcp-chunks/{chunk-E6RVTWJY.js → chunk-5YBCGQA7.js} +1 -1
  19. package/dist/mcp-chunks/{chunk-6D6KPSXN.js → chunk-AJPFOQLF.js} +1 -1
  20. package/dist/mcp-chunks/{chunk-C2PQFLWS.js → chunk-B4XFULJ6.js} +15 -6
  21. package/dist/mcp-chunks/{chunk-HAO6PL7Z.js → chunk-DIIFWDZ7.js} +7 -7
  22. package/dist/mcp-chunks/{chunk-55JIHDU3.js → chunk-EEYUPDRX.js} +1 -1
  23. package/dist/mcp-chunks/{chunk-7A63PAGP.js → chunk-ETYYCEQF.js} +21 -5
  24. package/dist/mcp-chunks/{chunk-E6T37ED6.js → chunk-FNQV2ONG.js} +2 -2
  25. package/dist/mcp-chunks/{chunk-2JHHONW4.js → chunk-FW5QVG6V.js} +1 -1
  26. package/dist/mcp-chunks/{chunk-YCYSQA5V.js → chunk-FZ7K5EGL.js} +5 -5
  27. package/dist/mcp-chunks/{chunk-KSMY7PXI.js → chunk-G5C4WVDQ.js} +1 -1
  28. package/dist/mcp-chunks/{chunk-XRGLP3Z2.js → chunk-GPCLDF6U.js} +1 -1
  29. package/dist/mcp-chunks/{chunk-KSGYBW3F.js → chunk-GQHTGV5E.js} +72 -22
  30. package/dist/mcp-chunks/{chunk-64EP2BVO.js → chunk-HULRE4D2.js} +1 -1
  31. package/dist/mcp-chunks/{chunk-UENXT3NE.js → chunk-ILSK6AWI.js} +1 -1
  32. package/dist/mcp-chunks/{chunk-RBVYCKCD.js → chunk-ILULMM2E.js} +2 -2
  33. package/dist/mcp-chunks/{chunk-NZOIX6XW.js → chunk-ITJWLDF5.js} +2 -2
  34. package/dist/mcp-chunks/{chunk-XUF6KARU.js → chunk-IUFDFNNP.js} +1 -1
  35. package/dist/mcp-chunks/chunk-JJG2OEHI.js +12 -0
  36. package/dist/mcp-chunks/{chunk-YPJ5EHXR.js → chunk-K56RW4HB.js} +4 -4
  37. package/dist/mcp-chunks/{chunk-H7F5RZXS.js → chunk-KJ3CMHWS.js} +2 -1
  38. package/dist/mcp-chunks/{chunk-WXBPMFSN.js → chunk-LI4L4FOV.js} +91 -34
  39. package/dist/mcp-chunks/{chunk-ETWN4IIA.js → chunk-LYZRCACV.js} +6 -6
  40. package/dist/mcp-chunks/{chunk-ZBFZ5UFE.js → chunk-MDVNQ4HM.js} +3 -1
  41. package/dist/mcp-chunks/{chunk-3IZQW4H4.js → chunk-MNAVFYYV.js} +212 -18
  42. package/dist/mcp-chunks/{chunk-7DH57OKF.js → chunk-MWD5PZ4G.js} +2 -2
  43. package/dist/mcp-chunks/{chunk-YSPT6F7K.js → chunk-N2HVJU7X.js} +1 -1
  44. package/dist/mcp-chunks/{chunk-WWO5WGH5.js → chunk-NACLB5YH.js} +5 -5
  45. package/dist/mcp-chunks/{chunk-QJACOI2W.js → chunk-NMF5S5DC.js} +4 -2
  46. package/dist/mcp-chunks/{chunk-54EWGONA.js → chunk-NPU7EMGE.js} +10 -6
  47. package/dist/mcp-chunks/{chunk-SFREPU3D.js → chunk-NSZY5WLR.js} +1 -1
  48. package/dist/mcp-chunks/{chunk-7RDLPFIO.js → chunk-QK6LUI5Q.js} +2 -2
  49. package/dist/mcp-chunks/{chunk-XTL4MHFH.js → chunk-QONTHFPO.js} +11 -7
  50. package/dist/mcp-chunks/{chunk-YTKRAHO6.js → chunk-RDOD354S.js} +4 -4
  51. package/dist/mcp-chunks/{chunk-2MEHGB7D.js → chunk-RXSZ2W6Y.js} +1 -1
  52. package/dist/mcp-chunks/{chunk-UHOKCTZT.js → chunk-RYAUNXFA.js} +1 -1
  53. package/dist/mcp-chunks/{chunk-GIF7LOYU.js → chunk-SCD2NAX5.js} +2 -2
  54. package/dist/mcp-chunks/{chunk-F3LL4EBL.js → chunk-SHZVDY6Z.js} +1 -1
  55. package/dist/mcp-chunks/{chunk-CNDY7WB4.js → chunk-TAVMVGD5.js} +2 -2
  56. package/dist/mcp-chunks/{chunk-JAKI24KR.js → chunk-U23EY5DN.js} +1 -1
  57. package/dist/mcp-chunks/{chunk-SB2UUURE.js → chunk-UAIJZBGL.js} +10 -10
  58. package/dist/mcp-chunks/{chunk-PKOJCYNA.js → chunk-UDG3RHKX.js} +2 -2
  59. package/dist/mcp-chunks/{chunk-CA5WFJZA.js → chunk-VC6SKXTI.js} +1 -1
  60. package/dist/mcp-chunks/chunk-VJ2TSA5R.js +818 -0
  61. package/dist/mcp-chunks/{chunk-FWP4RACK.js → chunk-VREKED5H.js} +2 -2
  62. package/dist/mcp-chunks/{chunk-2FSDGCHW.js → chunk-WKUCIR2F.js} +374 -527
  63. package/dist/mcp-chunks/chunk-XRRT3SZM.js +1931 -0
  64. package/dist/mcp-chunks/{chunk-GSZOK5TS.js → chunk-YDJ7E2PH.js} +3 -3
  65. package/dist/mcp-chunks/{chunk-LICH4Q7A.js → chunk-ZI44YPFF.js} +4 -4
  66. package/dist/mcp-chunks/{chunk-DEUU7WSN.js → chunk-ZNKNF2BV.js} +2 -2
  67. package/dist/mcp-chunks/{chunk-DXPHJFSA.js → chunk-ZSKQI4TS.js} +4 -4
  68. package/dist/mcp-chunks/{cli-E4P6SZLQ.js → cli-Z7KV4PCE.js} +70 -69
  69. package/dist/mcp-chunks/client-B3FMQNGF.js +21 -0
  70. package/dist/mcp-chunks/{config-command-MWF3RHPQ.js → config-command-XXCDOB3M.js} +27 -27
  71. package/dist/mcp-chunks/daemon-command-BAREANTC.js +35 -0
  72. package/dist/mcp-chunks/{dist-ZIPUENTM.js → dist-V4UB7RTR.js} +547 -402
  73. package/dist/mcp-chunks/{emit-ts-command-GOVJJ64A.js → emit-ts-command-FEHTMXXB.js} +16 -16
  74. package/dist/mcp-chunks/{generate-cli-runner-L5OQIMEY.js → generate-cli-runner-OA6XL77R.js} +49 -42
  75. package/dist/mcp-chunks/{inspect-cli-command-7OMMREPE.js → inspect-cli-command-UQKKE5VO.js} +9 -9
  76. package/dist/mcp-chunks/{launch-BWXPLPB7.js → launch-KMPDJOUH.js} +1 -1
  77. package/dist/mcp-chunks/{lifecycle-B5UC65PT.js → lifecycle-R3IP22MJ.js} +1 -1
  78. package/dist/mcp-chunks/{list-command-ZO4HVFQK.js → list-command-7ENYKBF6.js} +31 -31
  79. package/dist/mcp-chunks/{output-utils-M3TJ2N4M.js → output-utils-N75TOWBX.js} +3 -3
  80. package/dist/mcp-chunks/{prompt-CH6TK0bC-C7OTKGRD.js → prompt-CH6TK0bC-NSBYYJZH.js} +1 -1
  81. package/dist/mcp-chunks/{record-command-VD3HUQIC.js → record-command-XHPCL7IG.js} +5 -5
  82. package/dist/mcp-chunks/{replay-command-AX6IN7YD.js → replay-command-CB56L3ZA.js} +6 -6
  83. package/dist/mcp-chunks/{resource-command-JEZ2DW2G.js → resource-command-STEBHVT7.js} +9 -9
  84. package/dist/mcp-chunks/{result-utils-3YHYGS45.js → result-utils-UONY2KNY.js} +3 -3
  85. package/dist/mcp-chunks/runtime-Z45IVD24.js +39 -0
  86. package/dist/mcp-chunks/{runtime-wrapper-UREU7GC3.js → runtime-wrapper-SYYAQVO6.js} +6 -6
  87. package/dist/mcp-chunks/{serve-command-M47YZ6JN.js → serve-command-VYSFRZFE.js} +35 -27
  88. package/dist/mcp-chunks/{timeouts-THZRYP4B.js → timeouts-T3JP3MUF.js} +5 -3
  89. package/dist/mcp-chunks/{vault-command-53P7MLCB.js → vault-command-AJ3X7GDI.js} +58 -12
  90. package/dist/mcp-chunks/{webapi-PHEQZQKH.js → webapi-BLTNWSB2.js} +68 -60
  91. package/dist/mcp-daemon.js +30 -28
  92. package/dist/mcp-run-worker.js +30 -28
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +2 -1
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/pi-extension.d.ts +3 -0
  97. package/dist/pi-extension.d.ts.map +1 -1
  98. package/dist/pi-extension.js +27 -0
  99. package/dist/pi-extension.js.map +1 -1
  100. package/dist/run-controller.d.ts +3 -1
  101. package/dist/run-controller.d.ts.map +1 -1
  102. package/dist/run-controller.js +10 -0
  103. package/dist/run-controller.js.map +1 -1
  104. package/dist/session.d.ts +3 -1
  105. package/dist/session.d.ts.map +1 -1
  106. package/dist/session.js +4 -1
  107. package/dist/session.js.map +1 -1
  108. package/docs/host-api.md +12 -0
  109. package/docs/pi-extension.md +10 -0
  110. package/package.json +11 -11
  111. package/vendor/introspection-recipe-check/win32-x64/introspection-recipe-check.exe +0 -0
  112. package/dist/mcp-chunks/call-arguments-TX3F2TEE.js +0 -15
  113. package/dist/mcp-chunks/chunk-SRZZQ6TL.js +0 -266
  114. package/dist/mcp-chunks/client-2EJC4PLL.js +0 -18
  115. package/dist/mcp-chunks/daemon-command-6CJ26MKI.js +0 -33
  116. package/dist/mcp-chunks/runtime-HSYVOME7.js +0 -37
@@ -0,0 +1,818 @@
1
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
+ import {
3
+ buildOAuthPersistence,
4
+ buildStaticClientInformation,
5
+ oauthAccessTokenNeedsRefresh,
6
+ readCachedAccessTokenWithPersistence,
7
+ reconcilePersistedTokens,
8
+ withRefreshLock,
9
+ withRefreshRequestTimeout
10
+ } from "./chunk-MNAVFYYV.js";
11
+ import {
12
+ sameOAuthTokenGeneration
13
+ } from "./chunk-B4XFULJ6.js";
14
+ import {
15
+ isUnauthorizedError
16
+ } from "./chunk-MWD5PZ4G.js";
17
+ import {
18
+ IssuerMismatchError,
19
+ auth,
20
+ validateClientMetadataUrl
21
+ } from "./chunk-K56RW4HB.js";
22
+ import {
23
+ suppressBrowserLaunchFromEnv
24
+ } from "./chunk-JJG2OEHI.js";
25
+ import {
26
+ isFileLockTimeoutError
27
+ } from "./chunk-ETYYCEQF.js";
28
+
29
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/oauth.js
30
+ import { spawn } from "node:child_process";
31
+ import { createHash, randomUUID } from "node:crypto";
32
+ import http from "node:http";
33
+ import { URL } from "node:url";
34
+ var CALLBACK_HOST = "127.0.0.1";
35
+ var CALLBACK_PATH = "/callback";
36
+ var INTERACTIVE_AUTHORIZATION_TTL_MS = 3e5;
37
+ var OAuthRefreshUnavailableError = class extends Error {
38
+ serverName;
39
+ constructor(serverName, options) {
40
+ super(`Could not refresh OAuth credentials for '${serverName}'. Another process may be refreshing them, or the token endpoint is unreachable. Retry shortly; run 'mcporter auth ${serverName}' if it persists.`, options);
41
+ this.name = "OAuthRefreshUnavailableError";
42
+ this.serverName = serverName;
43
+ }
44
+ };
45
+ var BrowserLaunchSuppressedError = class extends Error {
46
+ serverName;
47
+ constructor(serverName) {
48
+ super(`Authorization required for '${serverName}' but browser launch is suppressed (MCPORTER_OAUTH_NO_BROWSER); run 'mcporter auth ${serverName} --no-browser' to authorize.`);
49
+ this.name = "BrowserLaunchSuppressedError";
50
+ this.serverName = serverName;
51
+ }
52
+ };
53
+ var OAuthRedirectUriMismatchError = class extends Error {
54
+ constructor(serverName) {
55
+ super(`OAuth client registration for '${serverName}' used an obsolete redirect URI.`);
56
+ this.name = "OAuthRedirectUriMismatchError";
57
+ }
58
+ };
59
+ function createDeferred() {
60
+ let resolve;
61
+ let reject;
62
+ const promise = new Promise((res, rej) => {
63
+ resolve = res;
64
+ reject = rej;
65
+ });
66
+ return { promise, resolve, reject };
67
+ }
68
+ function openExternal(url, platform = process.platform, launch = spawn) {
69
+ const stdio = "ignore";
70
+ try {
71
+ if (platform === "darwin") {
72
+ const child = launch("open", [url], { stdio, detached: true });
73
+ child.unref();
74
+ } else if (platform === "win32") {
75
+ const child = launch("rundll32", ["url.dll,FileProtocolHandler", url], {
76
+ stdio,
77
+ detached: true,
78
+ windowsHide: true
79
+ });
80
+ child.unref();
81
+ } else {
82
+ try {
83
+ const child = launch("xdg-open", [url], { stdio, detached: true });
84
+ child.on("error", () => {
85
+ });
86
+ child.unref();
87
+ } catch {
88
+ }
89
+ }
90
+ } catch {
91
+ }
92
+ }
93
+ var PersistentOAuthClientProvider = class _PersistentOAuthClientProvider {
94
+ definition;
95
+ usesDynamicPort;
96
+ options;
97
+ metadata;
98
+ logger;
99
+ persistence;
100
+ redirectUrlValue;
101
+ authorizationDeferred = null;
102
+ authorizationRedirectStarted = false;
103
+ // One interactive authorization transaction per provider: concurrent SDK auth() flows
104
+ // (background GET reconnect + bridged POST both hitting 401) must not each open a
105
+ // prompt, because only one persisted PKCE verifier can complete (issue #247).
106
+ interactiveAuthorization = null;
107
+ pendingVerifiersByChallenge = /* @__PURE__ */ new Map();
108
+ server;
109
+ constructor(definition, persistence, redirectUrl, logger, usesDynamicPort, options = {}) {
110
+ this.definition = definition;
111
+ this.usesDynamicPort = usesDynamicPort;
112
+ this.options = options;
113
+ this.redirectUrlValue = redirectUrl;
114
+ this.logger = logger;
115
+ this.persistence = persistence;
116
+ this.metadata = {
117
+ client_name: definition.clientName ?? `mcporter (${definition.name})`,
118
+ redirect_uris: [this.redirectUrlValue.toString()],
119
+ grant_types: ["authorization_code", "refresh_token"],
120
+ response_types: ["code"],
121
+ token_endpoint_auth_method: "none",
122
+ // Omit scope so the MCP SDK can derive it from the server's metadata
123
+ // (resource metadata scopes_supported or auth server scopes_supported).
124
+ // Hardcoding 'mcp:tools' breaks providers like Granola whose auth server
125
+ // does not recognise that scope value.
126
+ // If oauthScope is explicitly configured, prefer that exact value.
127
+ ...definition.oauthScope !== void 0 ? { scope: definition.oauthScope || void 0 } : {}
128
+ };
129
+ }
130
+ static async create(definition, logger, options = {}) {
131
+ validateClientMetadataUrl(definition.oauthClientMetadataUrl);
132
+ const persistence = await buildOAuthPersistence(definition, logger);
133
+ const server = http.createServer();
134
+ const overrideRedirect = definition.oauthRedirectUrl ? new URL(definition.oauthRedirectUrl) : null;
135
+ const listenHost = overrideRedirect?.hostname ?? CALLBACK_HOST;
136
+ const overridePort = overrideRedirect?.port ?? "";
137
+ const usesDynamicPort = !overrideRedirect || overridePort === "" || overridePort === "0";
138
+ const desiredPort = usesDynamicPort ? void 0 : Number.parseInt(overridePort, 10);
139
+ const callbackPath = overrideRedirect?.pathname && overrideRedirect.pathname !== "/" ? overrideRedirect.pathname : CALLBACK_PATH;
140
+ const port = await new Promise((resolve, reject) => {
141
+ server.listen(desiredPort ?? 0, listenHost, () => {
142
+ const address = server.address();
143
+ if (typeof address === "object" && address && "port" in address) {
144
+ resolve(address.port);
145
+ } else {
146
+ reject(new Error("Failed to determine callback port"));
147
+ }
148
+ });
149
+ server.once("error", (error) => reject(error));
150
+ });
151
+ const redirectUrl = overrideRedirect ? new URL(overrideRedirect.toString()) : new URL(`http://${listenHost}:${port}${callbackPath}`);
152
+ if (usesDynamicPort) {
153
+ redirectUrl.port = String(port);
154
+ }
155
+ if (!overrideRedirect || overrideRedirect.pathname === "/" || overrideRedirect.pathname === "") {
156
+ redirectUrl.pathname = callbackPath;
157
+ }
158
+ const provider = new _PersistentOAuthClientProvider(definition, persistence, redirectUrl, logger, usesDynamicPort, options);
159
+ provider.attachServer(server);
160
+ return {
161
+ provider,
162
+ close: async () => {
163
+ await provider.close();
164
+ }
165
+ };
166
+ }
167
+ // attachServer listens for the OAuth redirect and resolves/rejects the deferred code promise.
168
+ attachServer(server) {
169
+ this.server = server;
170
+ server.on("request", async (req, res) => {
171
+ try {
172
+ const url = req.url ?? "";
173
+ const parsed = new URL(url, this.redirectUrlValue);
174
+ const expectedPath = this.redirectUrlValue.pathname || "/callback";
175
+ if (parsed.pathname !== expectedPath) {
176
+ res.statusCode = 404;
177
+ res.end("Not found");
178
+ return;
179
+ }
180
+ const code = parsed.searchParams.get("code");
181
+ const error = parsed.searchParams.get("error");
182
+ const receivedState = parsed.searchParams.get("state");
183
+ const iss = parsed.searchParams.get("iss") ?? void 0;
184
+ const expectedState = await this.persistence.readState();
185
+ if (expectedState && receivedState !== expectedState) {
186
+ res.statusCode = 400;
187
+ res.setHeader("Content-Type", "text/html");
188
+ res.end("<html><body><h1>Authorization failed</h1><p>Invalid OAuth state</p></body></html>");
189
+ this.authorizationDeferred?.reject(new Error("Invalid OAuth state"));
190
+ this.authorizationDeferred = null;
191
+ this.clearInteractiveAuthorization();
192
+ return;
193
+ }
194
+ if (code) {
195
+ this.logger.info(`Received OAuth authorization code for ${this.definition.name}`);
196
+ res.statusCode = 200;
197
+ res.setHeader("Content-Type", "text/html");
198
+ res.end("<html><body><h1>Authorization successful</h1><p>You can return to the CLI.</p></body></html>");
199
+ this.authorizationDeferred?.resolve({ code, iss });
200
+ this.authorizationDeferred = null;
201
+ this.clearInteractiveAuthorization();
202
+ } else if (error) {
203
+ res.statusCode = 400;
204
+ res.setHeader("Content-Type", "text/html");
205
+ res.end("<html><body><h1>Authorization failed</h1><p>Return to the CLI for details.</p></body></html>");
206
+ this.authorizationDeferred?.reject(new Error("OAuth authorization failed."));
207
+ this.authorizationDeferred = null;
208
+ this.clearInteractiveAuthorization();
209
+ } else {
210
+ res.statusCode = 400;
211
+ res.end("Missing authorization code");
212
+ this.authorizationDeferred?.reject(new Error("Missing authorization code"));
213
+ this.authorizationDeferred = null;
214
+ this.clearInteractiveAuthorization();
215
+ }
216
+ } catch (error) {
217
+ this.authorizationDeferred?.reject(error);
218
+ this.authorizationDeferred = null;
219
+ this.clearInteractiveAuthorization();
220
+ }
221
+ });
222
+ }
223
+ get redirectUrl() {
224
+ return this.redirectUrlValue;
225
+ }
226
+ get clientMetadata() {
227
+ return this.metadata;
228
+ }
229
+ get clientMetadataUrl() {
230
+ return this.definition.oauthClientMetadataUrl;
231
+ }
232
+ async state() {
233
+ const existing = await this.persistence.readState();
234
+ if (existing) {
235
+ return existing;
236
+ }
237
+ const state = randomUUID();
238
+ await this.persistence.saveState(state);
239
+ return state;
240
+ }
241
+ async clientInformation(ctx) {
242
+ const staticClient = buildStaticClientInformation(this.definition, { redirectUrl: this.redirectUrlValue });
243
+ if (staticClient) {
244
+ return { ...staticClient, ...ctx ? { issuer: ctx.issuer } : {} };
245
+ }
246
+ const stored = await this.persistence.readClientInfo();
247
+ if (ctx && stored?.issuer && !issuersMatch(stored.issuer, ctx.issuer)) {
248
+ await this.persistence.clear("client");
249
+ this.logger.info(`Discarded OAuth client registration for ${this.definition.name} after issuer changed.`);
250
+ return void 0;
251
+ }
252
+ if (!stored) {
253
+ const tokens = await this.persistence.readTokens();
254
+ if (tokens && typeof tokens.refresh_token === "string" && oauthAccessTokenNeedsRefresh(tokens)) {
255
+ await this.persistence.clear("tokens");
256
+ this.logger.info(`Discarded expired OAuth tokens for ${this.definition.name} because no client registration is available.`);
257
+ }
258
+ }
259
+ return stored;
260
+ }
261
+ async saveClientInformation(clientInformation) {
262
+ await this.persistence.saveClientInfo(clientInformation);
263
+ }
264
+ async tokens(ctx) {
265
+ const stored = await this.persistence.readTokens();
266
+ if (ctx && stored?.issuer && !issuersMatch(stored.issuer, ctx.issuer)) {
267
+ await this.persistence.clear("tokens");
268
+ this.logger.info(`Discarded OAuth tokens for ${this.definition.name} after issuer changed.`);
269
+ return void 0;
270
+ }
271
+ return await this.refreshedTokens(stored);
272
+ }
273
+ /**
274
+ * Refreshes an expiring token under the cross-process refresh lock before the
275
+ * SDK sees it.
276
+ *
277
+ * This is the interception point for SDK-driven refresh. The SDK redeems a
278
+ * rotating refresh token itself whenever tokens() hands it an expired one.
279
+ * Returning an already-refreshed token starves the proactive branch, so the
280
+ * redemption happens once under the lock instead of racing every other
281
+ * process that shares the credential. The distinct fresh-token post-401 path
282
+ * is wrapped by onOAuthUnauthorized().
283
+ *
284
+ * The locked transaction is re-entrant per call chain, so an SDK auth() flow
285
+ * that already holds the lock does not deadlock on this read.
286
+ *
287
+ * Returning an expired token that still carries a refresh token is never
288
+ * safe here: the SDK redeems whenever this method yields a refresh token — it
289
+ * never checks expiry — so the redemption would land outside the lock. That
290
+ * cannot be avoided by withholding the refresh token either, because the SDK
291
+ * re-persists this method's return value when `issuer` is unset and would
292
+ * destroy the token instead. So when a due refresh does not produce a usable
293
+ * token, this fails the connect rather than offering a redeemable stale one.
294
+ */
295
+ async refreshedTokens(stored) {
296
+ if (!stored || this.definition.auth === "refreshable_bearer") {
297
+ return stored;
298
+ }
299
+ try {
300
+ await readCachedAccessTokenWithPersistence(this.definition, this.persistence);
301
+ } catch (error) {
302
+ this.logger.warn(`Could not refresh OAuth tokens for ${this.definition.name}: ${error instanceof Error ? error.message : String(error)}`);
303
+ }
304
+ const latest = await this.persistence.readTokens();
305
+ if (latest && typeof latest.refresh_token === "string" && oauthAccessTokenNeedsRefresh(latest)) {
306
+ throw new OAuthRefreshUnavailableError(this.definition.name);
307
+ }
308
+ return latest;
309
+ }
310
+ async saveTokens(tokens) {
311
+ await this.persistence.saveTokens(tokens);
312
+ this.logger.info(`Saved OAuth tokens for ${this.definition.name} (${this.persistence.describe()})`);
313
+ }
314
+ /**
315
+ * Keeps the SDK's post-401 refresh transaction inside the same cross-process
316
+ * lock as proactive refresh. The SDK supplies the exact tokens attached to
317
+ * the rejected request, so a waiter can distinguish its stale generation
318
+ * from the winner another process persisted while it waited.
319
+ */
320
+ async onOAuthUnauthorized(context, continueDefault) {
321
+ const rejected = context.presentedTokens;
322
+ if (!rejected) {
323
+ throw new OAuthRefreshUnavailableError(this.definition.name);
324
+ }
325
+ try {
326
+ await withRefreshLock(this.definition, async () => {
327
+ const latest = await reconcilePersistedTokens(this.definition, this.persistence);
328
+ if (!latest) {
329
+ throw new OAuthRefreshUnavailableError(this.definition.name);
330
+ }
331
+ if (!sameOAuthTokenGeneration(latest, rejected)) {
332
+ return;
333
+ }
334
+ await continueDefault({ fetchFn: withRefreshRequestTimeout(context.fetchFn) });
335
+ });
336
+ } catch (error) {
337
+ if (isFileLockTimeoutError(error)) {
338
+ throw new OAuthRefreshUnavailableError(this.definition.name, { cause: error });
339
+ }
340
+ throw error;
341
+ }
342
+ }
343
+ async redirectToAuthorization(authorizationUrl) {
344
+ await this.invalidateObsoleteDynamicRegistration();
345
+ this.authorizationRedirectStarted = true;
346
+ this.ensureAuthorizationDeferred();
347
+ const challenge = authorizationUrl.searchParams.get("code_challenge");
348
+ if (this.hasActiveInteractiveAuthorization()) {
349
+ if (challenge) {
350
+ this.pendingVerifiersByChallenge.delete(challenge);
351
+ }
352
+ this.logger.info(`Authorization already pending for ${this.definition.name}; suppressing duplicate prompt.`);
353
+ return;
354
+ }
355
+ this.interactiveAuthorization = { challenge, claimedAt: Date.now() };
356
+ const claimedVerifier = challenge ? this.pendingVerifiersByChallenge.get(challenge) : void 0;
357
+ if (challenge) {
358
+ this.pendingVerifiersByChallenge.delete(challenge);
359
+ }
360
+ if (claimedVerifier) {
361
+ await this.persistence.saveCodeVerifier(claimedVerifier);
362
+ }
363
+ const request = {
364
+ authorizationUrl: authorizationUrl.toString(),
365
+ redirectUrl: this.redirectUrlValue.toString()
366
+ };
367
+ if (this.options.suppressBrowserLaunch ?? suppressBrowserLaunchFromEnv()) {
368
+ if (this.options.onAuthorizationUrl) {
369
+ await this.options.onAuthorizationUrl(request);
370
+ return;
371
+ }
372
+ const suppressed = new BrowserLaunchSuppressedError(this.definition.name);
373
+ this.logger.warn(suppressed.message);
374
+ const deferred = this.ensureAuthorizationDeferred();
375
+ deferred.promise.catch(() => {
376
+ });
377
+ deferred.reject(suppressed);
378
+ this.clearInteractiveAuthorization();
379
+ return;
380
+ }
381
+ this.logger.info(`Authorization required for ${this.definition.name}. Opening browser...`);
382
+ __oauthInternals.openExternal(request.authorizationUrl);
383
+ this.logger.warn(`If the browser did not open, visit ${request.authorizationUrl} manually.`);
384
+ }
385
+ hasAuthorizationRedirectStarted() {
386
+ return this.authorizationRedirectStarted;
387
+ }
388
+ async saveCodeVerifier(codeVerifier) {
389
+ this.pendingVerifiersByChallenge.set(challengeForVerifier(codeVerifier), codeVerifier);
390
+ if (this.hasActiveInteractiveAuthorization()) {
391
+ return;
392
+ }
393
+ await this.persistence.saveCodeVerifier(codeVerifier);
394
+ }
395
+ async codeVerifier() {
396
+ const value = await this.persistence.readCodeVerifier();
397
+ if (!value) {
398
+ throw new Error(`Missing PKCE code verifier for ${this.definition.name}`);
399
+ }
400
+ return value.trim();
401
+ }
402
+ // invalidateCredentials removes cached files to force the next OAuth flow.
403
+ async invalidateCredentials(scope) {
404
+ if (scope === "all" || scope === "verifier") {
405
+ this.clearInteractiveAuthorization();
406
+ }
407
+ await this.persistence.clear(scope);
408
+ }
409
+ async saveDiscoveryState(state) {
410
+ await this.persistence.saveDiscoveryState(state);
411
+ }
412
+ async discoveryState() {
413
+ return this.persistence.readDiscoveryState();
414
+ }
415
+ async saveAuthorizationServerUrl(url) {
416
+ await this.persistence.saveAuthorizationServerUrl(url);
417
+ }
418
+ async authorizationServerUrl() {
419
+ return this.persistence.readAuthorizationServerUrl();
420
+ }
421
+ async saveResourceUrl(url) {
422
+ await this.persistence.saveResourceUrl(url);
423
+ }
424
+ async resourceUrl() {
425
+ return this.persistence.readResourceUrl();
426
+ }
427
+ // waitForAuthorizationCode resolves once the local callback server captures a redirect.
428
+ // The same deferred is shared with redirectToAuthorization so callback resolution is stable.
429
+ async waitForAuthorizationCode() {
430
+ return (await this.waitForAuthorizationResponse()).code;
431
+ }
432
+ async waitForAuthorizationResponse() {
433
+ return this.ensureAuthorizationDeferred().promise;
434
+ }
435
+ // close stops the temporary callback server created for the OAuth session.
436
+ async close() {
437
+ if (this.authorizationDeferred) {
438
+ this.authorizationDeferred.reject(new Error("OAuth session closed before receiving authorization code."));
439
+ this.authorizationDeferred = null;
440
+ this.clearInteractiveAuthorization();
441
+ }
442
+ if (!this.server) {
443
+ return;
444
+ }
445
+ this.server.closeAllConnections?.();
446
+ const server = this.server;
447
+ this.server = void 0;
448
+ await new Promise((resolve) => {
449
+ server.close(() => resolve());
450
+ });
451
+ }
452
+ ensureAuthorizationDeferred() {
453
+ if (!this.authorizationDeferred) {
454
+ this.authorizationDeferred = createDeferred();
455
+ }
456
+ return this.authorizationDeferred;
457
+ }
458
+ hasActiveInteractiveAuthorization() {
459
+ if (!this.interactiveAuthorization) {
460
+ return false;
461
+ }
462
+ if (Date.now() - this.interactiveAuthorization.claimedAt > INTERACTIVE_AUTHORIZATION_TTL_MS) {
463
+ this.interactiveAuthorization = null;
464
+ return false;
465
+ }
466
+ return true;
467
+ }
468
+ clearInteractiveAuthorization() {
469
+ this.interactiveAuthorization = null;
470
+ this.pendingVerifiersByChallenge.clear();
471
+ }
472
+ async invalidateObsoleteDynamicRegistration() {
473
+ if (!this.usesDynamicPort || this.definition.oauthClientId) {
474
+ return;
475
+ }
476
+ let snapshot;
477
+ try {
478
+ snapshot = await this.persistence.readSnapshot();
479
+ } catch (error) {
480
+ await this.close();
481
+ throw error;
482
+ }
483
+ const cachedClient = snapshot.clientInfo;
484
+ if (cachedClient?.client_id === this.definition.oauthClientMetadataUrl) {
485
+ return;
486
+ }
487
+ const cachedRedirect = firstRedirectUri(cachedClient);
488
+ if (!cachedClient || !cachedRedirect || cachedRedirect === this.redirectUrlValue.toString()) {
489
+ return;
490
+ }
491
+ this.logger.info(`Redirect URI changed (${cachedRedirect} \u2192 ${this.redirectUrlValue.toString()}); replacing obsolete client registration before interactive authorization.`);
492
+ try {
493
+ await this.persistence.clearRejectedCredentials(snapshot.tokens, cachedClient);
494
+ } catch (error) {
495
+ await this.close();
496
+ throw error;
497
+ }
498
+ throw new OAuthRedirectUriMismatchError(this.definition.name);
499
+ }
500
+ };
501
+ async function createOAuthSession(definition, logger, options = {}) {
502
+ const { provider, close } = await PersistentOAuthClientProvider.create(definition, logger, options);
503
+ const waitForAuthorizationCode = () => provider.waitForAuthorizationCode();
504
+ const waitForAuthorizationResponse = () => provider.waitForAuthorizationResponse();
505
+ const hasAuthorizationRedirectStarted = () => provider.hasAuthorizationRedirectStarted();
506
+ return {
507
+ provider,
508
+ waitForAuthorizationCode,
509
+ waitForAuthorizationResponse,
510
+ hasAuthorizationRedirectStarted,
511
+ close
512
+ };
513
+ }
514
+ function challengeForVerifier(verifier) {
515
+ return createHash("sha256").update(verifier).digest("base64url");
516
+ }
517
+ function firstRedirectUri(client) {
518
+ if (!client || typeof client !== "object") {
519
+ return void 0;
520
+ }
521
+ const redirectUris = client.redirect_uris;
522
+ if (!Array.isArray(redirectUris)) {
523
+ return void 0;
524
+ }
525
+ const [first] = redirectUris;
526
+ return typeof first === "string" ? first : void 0;
527
+ }
528
+ function issuersMatch(first, second) {
529
+ return first === second || first.endsWith("/") && first.slice(0, -1) === second || second.endsWith("/") && second.slice(0, -1) === first;
530
+ }
531
+ var __oauthInternals = {
532
+ openExternal
533
+ };
534
+
535
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/oauth.js
536
+ var DEFAULT_OAUTH_CODE_TIMEOUT_MS = 3e5;
537
+ var OAUTH_FLOW_ERROR = /* @__PURE__ */ Symbol("oauth-flow-error");
538
+ var POST_AUTH_CONNECT_ERROR = /* @__PURE__ */ Symbol("post-auth-connect-error");
539
+ var MAX_OAUTH_ERROR_DETAIL_LENGTH = 1200;
540
+ var PROACTIVE_TOKEN_SKEW_SECONDS = 60;
541
+ var OAuthTimeoutError = class extends Error {
542
+ timeoutMs;
543
+ serverName;
544
+ constructor(serverName, timeoutMs) {
545
+ const seconds = Math.round(timeoutMs / 1e3);
546
+ super(`OAuth authorization for '${serverName}' timed out after ${seconds}s; aborting.`);
547
+ this.name = "OAuthTimeoutError";
548
+ this.timeoutMs = timeoutMs;
549
+ this.serverName = serverName;
550
+ }
551
+ };
552
+ var OAuthAuthorizationNotStartedError = class extends Error {
553
+ serverName;
554
+ constructor(serverName, cause) {
555
+ const causeMessage = formatOAuthErrorDetail(cause);
556
+ const detail = causeMessage ? ` Last error: ${causeMessage}` : "";
557
+ super(`OAuth authorization for '${serverName}' did not produce an authorization URL; aborting instead of waiting for a browser callback.${detail}`);
558
+ this.name = "OAuthAuthorizationNotStartedError";
559
+ this.serverName = serverName;
560
+ }
561
+ };
562
+ function formatOAuthErrorDetail(cause) {
563
+ if (!(cause instanceof Error) || !cause.message) {
564
+ return "";
565
+ }
566
+ return truncateOAuthErrorDetail(cause.message);
567
+ }
568
+ function truncateOAuthErrorDetail(message) {
569
+ if (message.length <= MAX_OAUTH_ERROR_DETAIL_LENGTH) {
570
+ return message;
571
+ }
572
+ const truncated = message.length - MAX_OAUTH_ERROR_DETAIL_LENGTH;
573
+ return `${message.slice(0, MAX_OAUTH_ERROR_DETAIL_LENGTH)}... [truncated ${truncated} chars]`;
574
+ }
575
+ function markOAuthFlowError(error) {
576
+ return markError(error, OAUTH_FLOW_ERROR);
577
+ }
578
+ function isOAuthFlowError(error) {
579
+ return hasErrorMarker(error, OAUTH_FLOW_ERROR);
580
+ }
581
+ function markPostAuthConnectError(error) {
582
+ return markError(error, POST_AUTH_CONNECT_ERROR);
583
+ }
584
+ function isPostAuthConnectError(error) {
585
+ return hasErrorMarker(error, POST_AUTH_CONNECT_ERROR);
586
+ }
587
+ function markError(error, marker) {
588
+ if (!error || typeof error !== "object" && typeof error !== "function") {
589
+ return error;
590
+ }
591
+ Object.defineProperty(error, marker, {
592
+ value: true,
593
+ enumerable: false,
594
+ configurable: true
595
+ });
596
+ return error;
597
+ }
598
+ function hasErrorMarker(error, marker) {
599
+ return !!error && (typeof error === "object" || typeof error === "function") && marker in error && Boolean(error[marker]);
600
+ }
601
+ function hasUsableCachedAccessToken(tokens) {
602
+ if (!tokens || typeof tokens.access_token !== "string" || tokens.access_token.trim().length === 0) {
603
+ return false;
604
+ }
605
+ const stored = tokens;
606
+ const expiresAt = typeof stored.expires_at === "number" ? stored.expires_at : stored.expiresAt;
607
+ return typeof expiresAt === "number" && expiresAt > Math.floor(Date.now() / 1e3) + PROACTIVE_TOKEN_SKEW_SECONDS;
608
+ }
609
+ async function connectWithAuth(client, transport, session, logger, options = {}) {
610
+ const { serverName, maxAttempts = 3, oauthTimeoutMs = DEFAULT_OAUTH_CODE_TIMEOUT_MS, recreateTransport } = options;
611
+ const state = {
612
+ activeTransport: transport,
613
+ attempt: 0,
614
+ hasCompletedAuthFlow: false,
615
+ repairedRedirectMismatch: false
616
+ };
617
+ while (true) {
618
+ try {
619
+ await attemptTransportConnect(client, state, options.signal);
620
+ if (session && !state.hasCompletedAuthFlow && options.serverUrl) {
621
+ await completeProactiveAuthorization(state.activeTransport, session, logger, {
622
+ serverName,
623
+ oauthTimeoutMs,
624
+ serverUrl: options.serverUrl,
625
+ fetchFn: options.fetchFn
626
+ });
627
+ state.hasCompletedAuthFlow = true;
628
+ }
629
+ if (session && state.hasCompletedAuthFlow) {
630
+ await session.close().catch(() => {
631
+ });
632
+ }
633
+ return state.activeTransport;
634
+ } catch (error) {
635
+ if (error instanceof OAuthRedirectUriMismatchError) {
636
+ if (state.repairedRedirectMismatch || !recreateTransport) {
637
+ await closeReplacementTransport(transport, state.activeTransport);
638
+ throw markOAuthFlowError(error);
639
+ }
640
+ state.repairedRedirectMismatch = true;
641
+ state.activeTransport = await recreateOAuthTransport(state.activeTransport, recreateTransport);
642
+ continue;
643
+ }
644
+ const unauthorized = isUnauthorizedError(error);
645
+ if (!shouldRetryAuthorization(state, unauthorized, session)) {
646
+ await closeReplacementTransport(transport, state.activeTransport);
647
+ throw state.hasCompletedAuthFlow && !unauthorized ? markPostAuthConnectError(error) : error;
648
+ }
649
+ state.attempt += 1;
650
+ if (state.attempt > maxAttempts) {
651
+ await closeReplacementTransport(transport, state.activeTransport);
652
+ throw state.hasCompletedAuthFlow ? markPostAuthConnectError(error) : error;
653
+ }
654
+ if (session.hasAuthorizationRedirectStarted?.() !== false) {
655
+ logger.warn(`OAuth authorization required for '${serverName ?? "unknown"}'. Waiting for browser approval...`);
656
+ }
657
+ try {
658
+ state.activeTransport = await completeAuthorizationChallenge(state.activeTransport, session, logger, error, {
659
+ serverName,
660
+ oauthTimeoutMs,
661
+ recreateTransport
662
+ });
663
+ state.hasCompletedAuthFlow = true;
664
+ logger.info("Authorization code accepted. Retrying connection...");
665
+ } catch (authError) {
666
+ const message = authError instanceof OAuthAuthorizationNotStartedError ? "OAuth authorization could not start." : "OAuth authorization failed while waiting for callback.";
667
+ logger.error(message, authError);
668
+ await closeReplacementTransport(transport, state.activeTransport);
669
+ throw markOAuthFlowError(authError);
670
+ }
671
+ }
672
+ }
673
+ }
674
+ async function attemptTransportConnect(client, state, signal) {
675
+ if (signal) {
676
+ await client.connect(state.activeTransport, { signal });
677
+ } else {
678
+ await client.connect(state.activeTransport);
679
+ }
680
+ return state.activeTransport;
681
+ }
682
+ function shouldRetryAuthorization(_state, unauthorized, session) {
683
+ if (!session || !unauthorized) {
684
+ return false;
685
+ }
686
+ return true;
687
+ }
688
+ async function closeReplacementTransport(originalTransport, activeTransport) {
689
+ if (activeTransport === originalTransport) {
690
+ return;
691
+ }
692
+ await activeTransport.close().catch(() => {
693
+ });
694
+ }
695
+ async function recreateOAuthTransport(activeTransport, recreateTransport) {
696
+ const replacement = await recreateTransport(activeTransport);
697
+ await activeTransport.close().catch(() => {
698
+ });
699
+ return replacement;
700
+ }
701
+ async function completeAuthorizationChallenge(transport, session, logger, connectError, options) {
702
+ if (session.hasAuthorizationRedirectStarted?.() === false) {
703
+ throw new OAuthAuthorizationNotStartedError(options.serverName ?? "unknown", connectError);
704
+ }
705
+ const response = await waitForAuthorizationResponseWithTimeout(session, logger, options.serverName, options.oauthTimeoutMs ?? DEFAULT_OAUTH_CODE_TIMEOUT_MS);
706
+ if (typeof transport.finishAuth !== "function") {
707
+ logger.warn("Transport does not support finishAuth; cannot complete OAuth flow automatically.");
708
+ throw connectError;
709
+ }
710
+ await finishAuthorization(transport, response, options.serverName);
711
+ if (!options.recreateTransport) {
712
+ return transport;
713
+ }
714
+ const nextTransport = await options.recreateTransport(transport);
715
+ await transport.close().catch(() => {
716
+ });
717
+ return nextTransport;
718
+ }
719
+ async function completeProactiveAuthorization(transport, session, logger, options) {
720
+ const serverUrl = options.serverUrl;
721
+ if (!serverUrl) {
722
+ return;
723
+ }
724
+ try {
725
+ const cachedTokens = await session.provider.tokens?.();
726
+ if (hasUsableCachedAccessToken(cachedTokens)) {
727
+ return;
728
+ }
729
+ const runAuth = () => auth(session.provider, {
730
+ serverUrl,
731
+ fetchFn: options.fetchFn
732
+ });
733
+ let result;
734
+ try {
735
+ result = await runAuth();
736
+ } catch (error) {
737
+ if (!(error instanceof OAuthRedirectUriMismatchError)) {
738
+ throw error;
739
+ }
740
+ result = await runAuth();
741
+ }
742
+ if (result !== "REDIRECT") {
743
+ await session.close().catch(() => {
744
+ });
745
+ return;
746
+ }
747
+ if (session.hasAuthorizationRedirectStarted?.() === false) {
748
+ throw new OAuthAuthorizationNotStartedError(options.serverName ?? "unknown");
749
+ }
750
+ logger.warn(`OAuth authorization required for '${options.serverName ?? "unknown"}'. Waiting for browser approval...`);
751
+ if (typeof transport.finishAuth !== "function") {
752
+ throw new Error("Transport does not support finishAuth; cannot complete OAuth flow automatically.");
753
+ }
754
+ const response = await waitForAuthorizationResponseWithTimeout(session, logger, options.serverName, options.oauthTimeoutMs ?? DEFAULT_OAUTH_CODE_TIMEOUT_MS);
755
+ await finishAuthorization(transport, response, options.serverName);
756
+ await session.close().catch(() => {
757
+ });
758
+ } catch (error) {
759
+ throw markOAuthFlowError(error);
760
+ }
761
+ }
762
+ function waitForAuthorizationResponseWithTimeout(session, logger, serverName, timeoutMs = DEFAULT_OAUTH_CODE_TIMEOUT_MS) {
763
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
764
+ return readAuthorizationResponse(session);
765
+ }
766
+ const displayName = serverName ?? "unknown";
767
+ return new Promise((resolve, reject) => {
768
+ const timer = setTimeout(() => {
769
+ const error = new OAuthTimeoutError(displayName, timeoutMs);
770
+ logger.warn(error.message);
771
+ reject(error);
772
+ }, timeoutMs);
773
+ readAuthorizationResponse(session).then((response) => {
774
+ clearTimeout(timer);
775
+ resolve(response);
776
+ }, (error) => {
777
+ clearTimeout(timer);
778
+ reject(error);
779
+ });
780
+ });
781
+ }
782
+ async function readAuthorizationResponse(session) {
783
+ if (session.waitForAuthorizationResponse)
784
+ return session.waitForAuthorizationResponse();
785
+ return { code: await session.waitForAuthorizationCode() };
786
+ }
787
+ async function finishAuthorization(transport, response, serverName) {
788
+ try {
789
+ await transport.finishAuth?.(response.code, response.iss);
790
+ } catch (error) {
791
+ if (error instanceof IssuerMismatchError && error.kind === "authorization_response") {
792
+ throw new Error(`OAuth issuer validation failed for '${serverName ?? "unknown"}': expected ${JSON.stringify(error.expected)}, got ${JSON.stringify(error.received)}; the authorization code was not redeemed.`, { cause: error });
793
+ }
794
+ throw error;
795
+ }
796
+ }
797
+ function parseOAuthTimeout(raw) {
798
+ if (!raw) {
799
+ return DEFAULT_OAUTH_CODE_TIMEOUT_MS;
800
+ }
801
+ const parsed = Number.parseInt(raw, 10);
802
+ if (!Number.isFinite(parsed) || parsed <= 0) {
803
+ return DEFAULT_OAUTH_CODE_TIMEOUT_MS;
804
+ }
805
+ return parsed;
806
+ }
807
+ function resolveOAuthTimeoutFromEnv() {
808
+ return parseOAuthTimeout(process.env.MCPORTER_OAUTH_TIMEOUT_MS ?? process.env.MCPORTER_OAUTH_TIMEOUT);
809
+ }
810
+
811
+ export {
812
+ createOAuthSession,
813
+ OAuthTimeoutError,
814
+ isOAuthFlowError,
815
+ isPostAuthConnectError,
816
+ connectWithAuth,
817
+ resolveOAuthTimeoutFromEnv
818
+ };