@lovable.dev/mcp-js 0.21.0-rc.0 → 0.21.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{base-RSqYamjy.d.ts → base-DTtaX5Rf.d.ts} +1 -1
- package/dist/{chunk-2LLCWLQL.js → chunk-4H3Y2KYT.js} +1 -1
- package/dist/{chunk-NQZGVZ24.js → chunk-7TVARTF4.js} +1 -1
- package/dist/{chunk-VTIP6LMI.js → chunk-IRCVDFWG.js} +34 -33
- package/dist/{chunk-XOCASA3L.js → chunk-OIRVEGPQ.js} +1 -1
- package/dist/{chunk-M2TRF6OJ.js → chunk-WOKM6B6H.js} +1 -1
- package/dist/{chunk-KYKL5ECH.js → chunk-YE6N7XLA.js} +1 -1
- package/dist/cli/extract-manifest.cjs +1 -1
- package/dist/cli/extract-manifest.js +3 -3
- package/dist/protocols/mcp/index.cjs +33 -32
- package/dist/protocols/mcp/index.d.cts +1 -1
- package/dist/protocols/mcp/index.d.ts +1 -1
- package/dist/protocols/mcp/index.js +3 -3
- package/dist/protocols/oauth-metadata.cjs +27 -26
- package/dist/protocols/oauth-metadata.js +3 -3
- package/dist/protocols/rest/index.cjs +33 -32
- package/dist/protocols/rest/index.d.cts +1 -1
- package/dist/protocols/rest/index.d.ts +1 -1
- package/dist/protocols/rest/index.js +4 -4
- package/dist/stacks/supabase/index.cjs +32 -31
- package/dist/stacks/supabase/index.js +6 -6
- package/dist/stacks/supabase/vite.cjs +1 -1
- package/dist/stacks/supabase/vite.js +1 -1
- package/dist/stacks/tanstack/index.cjs +32 -31
- package/dist/stacks/tanstack/index.js +6 -6
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "
|
|
1
|
+
type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_discovery_config_error" | "auth_discovery_unreachable" | "auth_jwks_config_error" | "auth_jwks_unreachable";
|
|
2
2
|
/** One recorded MCP call. Carries no arguments or response payloads — only the
|
|
3
3
|
* tool name, the JSON-RPC method, the result class, timing, and byte sizes. */
|
|
4
4
|
interface InvocationRecord {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./chunk-6DXGZZA4.js";
|
|
14
14
|
import {
|
|
15
15
|
version
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-OIRVEGPQ.js";
|
|
17
17
|
|
|
18
18
|
// src/core/http.ts
|
|
19
19
|
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
@@ -284,14 +284,16 @@ function cachedPromise(load, label) {
|
|
|
284
284
|
|
|
285
285
|
// src/auth/discovery.ts
|
|
286
286
|
var OAuthConfigurationError = class extends Error {
|
|
287
|
-
constructor(message) {
|
|
287
|
+
constructor(message, stage) {
|
|
288
288
|
super(message);
|
|
289
|
+
this.stage = stage;
|
|
289
290
|
this.name = "OAuthConfigurationError";
|
|
290
291
|
}
|
|
291
292
|
};
|
|
292
293
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
293
|
-
constructor(message) {
|
|
294
|
+
constructor(message, stage) {
|
|
294
295
|
super(message);
|
|
296
|
+
this.stage = stage;
|
|
295
297
|
this.name = "OAuthUpstreamUnreachableError";
|
|
296
298
|
}
|
|
297
299
|
};
|
|
@@ -325,32 +327,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
325
327
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
326
328
|
}
|
|
327
329
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
|
|
330
|
+
const errors = [];
|
|
331
|
+
for (const url of metadataUrls) {
|
|
332
|
+
try {
|
|
333
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
336
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
337
|
+
errors.push(error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
341
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
342
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
343
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
344
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
345
|
+
}
|
|
346
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
349
347
|
log.debug("oauth.discovery.fetch", { url });
|
|
350
348
|
let response;
|
|
351
349
|
try {
|
|
352
350
|
response = await fetch(url, {
|
|
353
|
-
signal: AbortSignal.
|
|
351
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
354
352
|
redirect: "manual"
|
|
355
353
|
});
|
|
356
354
|
} catch (err) {
|
|
@@ -385,14 +383,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
385
383
|
...describeError(err),
|
|
386
384
|
outcome: "503 authorization server unreachable"
|
|
387
385
|
});
|
|
388
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
386
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
389
387
|
}
|
|
390
388
|
log.error("oauth.discovery.config_error", {
|
|
391
389
|
issuer,
|
|
392
390
|
...describeError(err),
|
|
393
391
|
outcome: "500 oauth configuration error"
|
|
394
392
|
});
|
|
395
|
-
throw new OAuthConfigurationError(message);
|
|
393
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
396
394
|
}
|
|
397
395
|
}
|
|
398
396
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -463,7 +461,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
463
461
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
464
462
|
} catch (err) {
|
|
465
463
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
466
|
-
throw new OAuthUpstreamUnreachableError(
|
|
464
|
+
throw new OAuthUpstreamUnreachableError(
|
|
465
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
466
|
+
"jwks"
|
|
467
|
+
);
|
|
467
468
|
}
|
|
468
469
|
try {
|
|
469
470
|
if (!response.ok)
|
|
@@ -472,7 +473,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
472
473
|
return createLocalJWKSet(json);
|
|
473
474
|
} catch (err) {
|
|
474
475
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
475
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
476
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
476
477
|
}
|
|
477
478
|
}
|
|
478
479
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -685,21 +686,21 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
685
686
|
return { ok: true, auth };
|
|
686
687
|
} catch (err) {
|
|
687
688
|
if (err instanceof OAuthUpstreamUnreachableError) {
|
|
688
|
-
log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
|
|
689
|
+
log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
|
|
689
690
|
await recorder?.emit({
|
|
690
691
|
tool: null,
|
|
691
692
|
method: "authorize",
|
|
692
|
-
outcome: "
|
|
693
|
+
outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
|
|
693
694
|
durationMs: nowMs() - startedAt
|
|
694
695
|
});
|
|
695
696
|
return { ok: false, response: oauthUpstreamUnreachableResponse() };
|
|
696
697
|
}
|
|
697
698
|
if (err instanceof OAuthConfigurationError) {
|
|
698
|
-
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
699
|
+
log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
|
|
699
700
|
await recorder?.emit({
|
|
700
701
|
tool: null,
|
|
701
702
|
method: "authorize",
|
|
702
|
-
outcome: "
|
|
703
|
+
outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
|
|
703
704
|
durationMs: nowMs() - startedAt
|
|
704
705
|
});
|
|
705
706
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
methodNotAllowed,
|
|
11
11
|
nowMs,
|
|
12
12
|
withCors
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IRCVDFWG.js";
|
|
14
14
|
|
|
15
15
|
// src/protocols/rest/invoke-tool.ts
|
|
16
16
|
import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
buildMcpListing
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-YE6N7XLA.js";
|
|
5
|
+
import "../chunk-IRCVDFWG.js";
|
|
6
6
|
import "../chunk-H37EB22A.js";
|
|
7
7
|
import "../chunk-6DXGZZA4.js";
|
|
8
8
|
import {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "../chunk-Y3ZFPEQH.js";
|
|
11
11
|
import {
|
|
12
12
|
version
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-OIRVEGPQ.js";
|
|
14
14
|
|
|
15
15
|
// src/manifest/io.ts
|
|
16
16
|
import { randomUUID } from "crypto";
|
|
@@ -148,14 +148,16 @@ function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
|
148
148
|
|
|
149
149
|
// src/auth/discovery.ts
|
|
150
150
|
var OAuthConfigurationError = class extends Error {
|
|
151
|
-
constructor(message) {
|
|
151
|
+
constructor(message, stage) {
|
|
152
152
|
super(message);
|
|
153
|
+
this.stage = stage;
|
|
153
154
|
this.name = "OAuthConfigurationError";
|
|
154
155
|
}
|
|
155
156
|
};
|
|
156
157
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
157
|
-
constructor(message) {
|
|
158
|
+
constructor(message, stage) {
|
|
158
159
|
super(message);
|
|
160
|
+
this.stage = stage;
|
|
159
161
|
this.name = "OAuthUpstreamUnreachableError";
|
|
160
162
|
}
|
|
161
163
|
};
|
|
@@ -189,32 +191,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
189
191
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
190
192
|
}
|
|
191
193
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
|
|
194
|
+
const errors = [];
|
|
195
|
+
for (const url of metadataUrls) {
|
|
196
|
+
try {
|
|
197
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
198
|
+
} catch (err) {
|
|
199
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
200
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
201
|
+
errors.push(error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
205
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
206
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
207
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
208
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
209
|
+
}
|
|
210
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
213
211
|
log.debug("oauth.discovery.fetch", { url });
|
|
214
212
|
let response;
|
|
215
213
|
try {
|
|
216
214
|
response = await fetch(url, {
|
|
217
|
-
signal: AbortSignal.
|
|
215
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
218
216
|
redirect: "manual"
|
|
219
217
|
});
|
|
220
218
|
} catch (err) {
|
|
@@ -249,14 +247,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
249
247
|
...describeError(err),
|
|
250
248
|
outcome: "503 authorization server unreachable"
|
|
251
249
|
});
|
|
252
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
250
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
253
251
|
}
|
|
254
252
|
log.error("oauth.discovery.config_error", {
|
|
255
253
|
issuer,
|
|
256
254
|
...describeError(err),
|
|
257
255
|
outcome: "500 oauth configuration error"
|
|
258
256
|
});
|
|
259
|
-
throw new OAuthConfigurationError(message);
|
|
257
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
260
258
|
}
|
|
261
259
|
}
|
|
262
260
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -354,7 +352,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
354
352
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
355
353
|
} catch (err) {
|
|
356
354
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
357
|
-
throw new OAuthUpstreamUnreachableError(
|
|
355
|
+
throw new OAuthUpstreamUnreachableError(
|
|
356
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
357
|
+
"jwks"
|
|
358
|
+
);
|
|
358
359
|
}
|
|
359
360
|
try {
|
|
360
361
|
if (!response.ok)
|
|
@@ -363,7 +364,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
363
364
|
return (0, import_jose.createLocalJWKSet)(json);
|
|
364
365
|
} catch (err) {
|
|
365
366
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
366
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
367
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
367
368
|
}
|
|
368
369
|
}
|
|
369
370
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -568,21 +569,21 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
568
569
|
return { ok: true, auth };
|
|
569
570
|
} catch (err) {
|
|
570
571
|
if (err instanceof OAuthUpstreamUnreachableError) {
|
|
571
|
-
log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
|
|
572
|
+
log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
|
|
572
573
|
await recorder?.emit({
|
|
573
574
|
tool: null,
|
|
574
575
|
method: "authorize",
|
|
575
|
-
outcome: "
|
|
576
|
+
outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
|
|
576
577
|
durationMs: nowMs() - startedAt
|
|
577
578
|
});
|
|
578
579
|
return { ok: false, response: oauthUpstreamUnreachableResponse() };
|
|
579
580
|
}
|
|
580
581
|
if (err instanceof OAuthConfigurationError) {
|
|
581
|
-
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
582
|
+
log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
|
|
582
583
|
await recorder?.emit({
|
|
583
584
|
tool: null,
|
|
584
585
|
method: "authorize",
|
|
585
|
-
outcome: "
|
|
586
|
+
outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
|
|
586
587
|
durationMs: nowMs() - startedAt
|
|
587
588
|
});
|
|
588
589
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-CPkhCRxc.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../base-
|
|
3
|
+
import { M as MetricsRecorder } from '../../base-DTtaX5Rf.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-CPkhCRxc.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../base-
|
|
3
|
+
import { M as MetricsRecorder } from '../../base-DTtaX5Rf.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpProtocolHandler
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-4H3Y2KYT.js";
|
|
4
4
|
import "../../chunk-MA5H6PSF.js";
|
|
5
|
-
import "../../chunk-
|
|
5
|
+
import "../../chunk-IRCVDFWG.js";
|
|
6
6
|
import "../../chunk-H37EB22A.js";
|
|
7
7
|
import "../../chunk-6DXGZZA4.js";
|
|
8
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-OIRVEGPQ.js";
|
|
9
9
|
export {
|
|
10
10
|
createMcpProtocolHandler
|
|
11
11
|
};
|
|
@@ -143,14 +143,16 @@ function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
|
143
143
|
|
|
144
144
|
// src/auth/discovery.ts
|
|
145
145
|
var OAuthConfigurationError = class extends Error {
|
|
146
|
-
constructor(message) {
|
|
146
|
+
constructor(message, stage) {
|
|
147
147
|
super(message);
|
|
148
|
+
this.stage = stage;
|
|
148
149
|
this.name = "OAuthConfigurationError";
|
|
149
150
|
}
|
|
150
151
|
};
|
|
151
152
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
152
|
-
constructor(message) {
|
|
153
|
+
constructor(message, stage) {
|
|
153
154
|
super(message);
|
|
155
|
+
this.stage = stage;
|
|
154
156
|
this.name = "OAuthUpstreamUnreachableError";
|
|
155
157
|
}
|
|
156
158
|
};
|
|
@@ -184,32 +186,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
184
186
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
185
187
|
}
|
|
186
188
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
controller.abort();
|
|
197
|
-
return metadata;
|
|
198
|
-
} catch (aggregate) {
|
|
199
|
-
const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
|
|
200
|
-
const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
|
|
201
|
-
const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
|
|
202
|
-
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
203
|
-
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
204
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
189
|
+
const errors = [];
|
|
190
|
+
for (const url of metadataUrls) {
|
|
191
|
+
try {
|
|
192
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
195
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
196
|
+
errors.push(error);
|
|
197
|
+
}
|
|
205
198
|
}
|
|
199
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
200
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
201
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
202
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
203
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
206
204
|
}
|
|
207
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer
|
|
205
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
208
206
|
log.debug("oauth.discovery.fetch", { url });
|
|
209
207
|
let response;
|
|
210
208
|
try {
|
|
211
209
|
response = await fetch(url, {
|
|
212
|
-
signal: AbortSignal.
|
|
210
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
213
211
|
redirect: "manual"
|
|
214
212
|
});
|
|
215
213
|
} catch (err) {
|
|
@@ -244,14 +242,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
244
242
|
...describeError(err),
|
|
245
243
|
outcome: "503 authorization server unreachable"
|
|
246
244
|
});
|
|
247
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
245
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
248
246
|
}
|
|
249
247
|
log.error("oauth.discovery.config_error", {
|
|
250
248
|
issuer,
|
|
251
249
|
...describeError(err),
|
|
252
250
|
outcome: "500 oauth configuration error"
|
|
253
251
|
});
|
|
254
|
-
throw new OAuthConfigurationError(message);
|
|
252
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
255
253
|
}
|
|
256
254
|
}
|
|
257
255
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -346,7 +344,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
346
344
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
347
345
|
} catch (err) {
|
|
348
346
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
349
|
-
throw new OAuthUpstreamUnreachableError(
|
|
347
|
+
throw new OAuthUpstreamUnreachableError(
|
|
348
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
349
|
+
"jwks"
|
|
350
|
+
);
|
|
350
351
|
}
|
|
351
352
|
try {
|
|
352
353
|
if (!response.ok)
|
|
@@ -355,7 +356,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
355
356
|
return (0, import_jose.createLocalJWKSet)(json);
|
|
356
357
|
} catch (err) {
|
|
357
358
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
358
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
359
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
359
360
|
}
|
|
360
361
|
}
|
|
361
362
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createOAuthProtectedResourceMetadataHandler
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-7TVARTF4.js";
|
|
4
|
+
import "../chunk-IRCVDFWG.js";
|
|
5
5
|
import "../chunk-H37EB22A.js";
|
|
6
6
|
import "../chunk-6DXGZZA4.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-OIRVEGPQ.js";
|
|
8
8
|
export {
|
|
9
9
|
createOAuthProtectedResourceMetadataHandler
|
|
10
10
|
};
|
|
@@ -158,14 +158,16 @@ function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
|
158
158
|
|
|
159
159
|
// src/auth/discovery.ts
|
|
160
160
|
var OAuthConfigurationError = class extends Error {
|
|
161
|
-
constructor(message) {
|
|
161
|
+
constructor(message, stage) {
|
|
162
162
|
super(message);
|
|
163
|
+
this.stage = stage;
|
|
163
164
|
this.name = "OAuthConfigurationError";
|
|
164
165
|
}
|
|
165
166
|
};
|
|
166
167
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
167
|
-
constructor(message) {
|
|
168
|
+
constructor(message, stage) {
|
|
168
169
|
super(message);
|
|
170
|
+
this.stage = stage;
|
|
169
171
|
this.name = "OAuthUpstreamUnreachableError";
|
|
170
172
|
}
|
|
171
173
|
};
|
|
@@ -199,32 +201,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
199
201
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
200
202
|
}
|
|
201
203
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer, signal) {
|
|
204
|
+
const errors = [];
|
|
205
|
+
for (const url of metadataUrls) {
|
|
206
|
+
try {
|
|
207
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
210
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
211
|
+
errors.push(error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
215
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
216
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
217
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
218
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
219
|
+
}
|
|
220
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
223
221
|
log.debug("oauth.discovery.fetch", { url });
|
|
224
222
|
let response;
|
|
225
223
|
try {
|
|
226
224
|
response = await fetch(url, {
|
|
227
|
-
signal: AbortSignal.
|
|
225
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
228
226
|
redirect: "manual"
|
|
229
227
|
});
|
|
230
228
|
} catch (err) {
|
|
@@ -259,14 +257,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
259
257
|
...describeError(err),
|
|
260
258
|
outcome: "503 authorization server unreachable"
|
|
261
259
|
});
|
|
262
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
260
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
263
261
|
}
|
|
264
262
|
log.error("oauth.discovery.config_error", {
|
|
265
263
|
issuer,
|
|
266
264
|
...describeError(err),
|
|
267
265
|
outcome: "500 oauth configuration error"
|
|
268
266
|
});
|
|
269
|
-
throw new OAuthConfigurationError(message);
|
|
267
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
270
268
|
}
|
|
271
269
|
}
|
|
272
270
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -364,7 +362,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
364
362
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
365
363
|
} catch (err) {
|
|
366
364
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
367
|
-
throw new OAuthUpstreamUnreachableError(
|
|
365
|
+
throw new OAuthUpstreamUnreachableError(
|
|
366
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
367
|
+
"jwks"
|
|
368
|
+
);
|
|
368
369
|
}
|
|
369
370
|
try {
|
|
370
371
|
if (!response.ok)
|
|
@@ -373,7 +374,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
373
374
|
return (0, import_jose.createLocalJWKSet)(json);
|
|
374
375
|
} catch (err) {
|
|
375
376
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
376
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
377
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
377
378
|
}
|
|
378
379
|
}
|
|
379
380
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -586,21 +587,21 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
586
587
|
return { ok: true, auth };
|
|
587
588
|
} catch (err) {
|
|
588
589
|
if (err instanceof OAuthUpstreamUnreachableError) {
|
|
589
|
-
log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
|
|
590
|
+
log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
|
|
590
591
|
await recorder?.emit({
|
|
591
592
|
tool: null,
|
|
592
593
|
method: "authorize",
|
|
593
|
-
outcome: "
|
|
594
|
+
outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
|
|
594
595
|
durationMs: nowMs() - startedAt
|
|
595
596
|
});
|
|
596
597
|
return { ok: false, response: oauthUpstreamUnreachableResponse() };
|
|
597
598
|
}
|
|
598
599
|
if (err instanceof OAuthConfigurationError) {
|
|
599
|
-
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
600
|
+
log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
|
|
600
601
|
await recorder?.emit({
|
|
601
602
|
tool: null,
|
|
602
603
|
method: "authorize",
|
|
603
|
-
outcome: "
|
|
604
|
+
outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
|
|
604
605
|
durationMs: nowMs() - startedAt
|
|
605
606
|
});
|
|
606
607
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-CPkhCRxc.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../base-
|
|
3
|
+
import { M as MetricsRecorder } from '../../base-DTtaX5Rf.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-CPkhCRxc.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../base-
|
|
3
|
+
import { M as MetricsRecorder } from '../../base-DTtaX5Rf.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createInvokeToolHandler
|
|
3
|
-
} from "../../chunk-
|
|
3
|
+
} from "../../chunk-WOKM6B6H.js";
|
|
4
4
|
import {
|
|
5
5
|
createListToolsHandler
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-YE6N7XLA.js";
|
|
7
7
|
import "../../chunk-MA5H6PSF.js";
|
|
8
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-IRCVDFWG.js";
|
|
9
9
|
import "../../chunk-H37EB22A.js";
|
|
10
10
|
import "../../chunk-6DXGZZA4.js";
|
|
11
|
-
import "../../chunk-
|
|
11
|
+
import "../../chunk-OIRVEGPQ.js";
|
|
12
12
|
export {
|
|
13
13
|
createInvokeToolHandler,
|
|
14
14
|
createListToolsHandler
|
|
@@ -174,7 +174,7 @@ function describeError(err) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// package.json
|
|
177
|
-
var version = "0.21.0-rc.
|
|
177
|
+
var version = "0.21.0-rc.2";
|
|
178
178
|
|
|
179
179
|
// src/metrics/otlp.ts
|
|
180
180
|
var SCOPE_NAME = "@lovable.dev/mcp-js";
|
|
@@ -440,14 +440,16 @@ function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
|
440
440
|
|
|
441
441
|
// src/auth/discovery.ts
|
|
442
442
|
var OAuthConfigurationError = class extends Error {
|
|
443
|
-
constructor(message) {
|
|
443
|
+
constructor(message, stage) {
|
|
444
444
|
super(message);
|
|
445
|
+
this.stage = stage;
|
|
445
446
|
this.name = "OAuthConfigurationError";
|
|
446
447
|
}
|
|
447
448
|
};
|
|
448
449
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
449
|
-
constructor(message) {
|
|
450
|
+
constructor(message, stage) {
|
|
450
451
|
super(message);
|
|
452
|
+
this.stage = stage;
|
|
451
453
|
this.name = "OAuthUpstreamUnreachableError";
|
|
452
454
|
}
|
|
453
455
|
};
|
|
@@ -481,32 +483,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
481
483
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
482
484
|
}
|
|
483
485
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
484
|
-
const
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
controller.abort();
|
|
494
|
-
return metadata;
|
|
495
|
-
} catch (aggregate) {
|
|
496
|
-
const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
|
|
497
|
-
const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
|
|
498
|
-
const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
|
|
499
|
-
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
500
|
-
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
501
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
486
|
+
const errors = [];
|
|
487
|
+
for (const url of metadataUrls) {
|
|
488
|
+
try {
|
|
489
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
490
|
+
} catch (err) {
|
|
491
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
492
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
493
|
+
errors.push(error);
|
|
494
|
+
}
|
|
502
495
|
}
|
|
496
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
497
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
498
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
499
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
500
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
503
501
|
}
|
|
504
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer
|
|
502
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
505
503
|
log.debug("oauth.discovery.fetch", { url });
|
|
506
504
|
let response;
|
|
507
505
|
try {
|
|
508
506
|
response = await fetch(url, {
|
|
509
|
-
signal: AbortSignal.
|
|
507
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
510
508
|
redirect: "manual"
|
|
511
509
|
});
|
|
512
510
|
} catch (err) {
|
|
@@ -541,14 +539,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
541
539
|
...describeError(err),
|
|
542
540
|
outcome: "503 authorization server unreachable"
|
|
543
541
|
});
|
|
544
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
542
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
545
543
|
}
|
|
546
544
|
log.error("oauth.discovery.config_error", {
|
|
547
545
|
issuer,
|
|
548
546
|
...describeError(err),
|
|
549
547
|
outcome: "500 oauth configuration error"
|
|
550
548
|
});
|
|
551
|
-
throw new OAuthConfigurationError(message);
|
|
549
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
552
550
|
}
|
|
553
551
|
}
|
|
554
552
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -619,7 +617,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
619
617
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
620
618
|
} catch (err) {
|
|
621
619
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
622
|
-
throw new OAuthUpstreamUnreachableError(
|
|
620
|
+
throw new OAuthUpstreamUnreachableError(
|
|
621
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
622
|
+
"jwks"
|
|
623
|
+
);
|
|
623
624
|
}
|
|
624
625
|
try {
|
|
625
626
|
if (!response.ok)
|
|
@@ -628,7 +629,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
628
629
|
return (0, import_jose.createLocalJWKSet)(json);
|
|
629
630
|
} catch (err) {
|
|
630
631
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
631
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
632
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
632
633
|
}
|
|
633
634
|
}
|
|
634
635
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -841,21 +842,21 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
841
842
|
return { ok: true, auth };
|
|
842
843
|
} catch (err) {
|
|
843
844
|
if (err instanceof OAuthUpstreamUnreachableError) {
|
|
844
|
-
log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
|
|
845
|
+
log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
|
|
845
846
|
await recorder?.emit({
|
|
846
847
|
tool: null,
|
|
847
848
|
method: "authorize",
|
|
848
|
-
outcome: "
|
|
849
|
+
outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
|
|
849
850
|
durationMs: nowMs() - startedAt
|
|
850
851
|
});
|
|
851
852
|
return { ok: false, response: oauthUpstreamUnreachableResponse() };
|
|
852
853
|
}
|
|
853
854
|
if (err instanceof OAuthConfigurationError) {
|
|
854
|
-
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
855
|
+
log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
|
|
855
856
|
await recorder?.emit({
|
|
856
857
|
tool: null,
|
|
857
858
|
method: "authorize",
|
|
858
|
-
outcome: "
|
|
859
|
+
outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
|
|
859
860
|
durationMs: nowMs() - startedAt
|
|
860
861
|
});
|
|
861
862
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
@@ -3,21 +3,21 @@ import {
|
|
|
3
3
|
} from "../../chunk-UQK5UO6C.js";
|
|
4
4
|
import {
|
|
5
5
|
createMcpProtocolHandler
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-4H3Y2KYT.js";
|
|
7
7
|
import {
|
|
8
8
|
createOAuthProtectedResourceMetadataHandler
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-7TVARTF4.js";
|
|
10
10
|
import {
|
|
11
11
|
createInvokeToolHandler
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-WOKM6B6H.js";
|
|
13
13
|
import {
|
|
14
14
|
createListToolsHandler
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-YE6N7XLA.js";
|
|
16
16
|
import "../../chunk-MA5H6PSF.js";
|
|
17
17
|
import {
|
|
18
18
|
assertResourcePathShape,
|
|
19
19
|
createRecorderForRuntime
|
|
20
|
-
} from "../../chunk-
|
|
20
|
+
} from "../../chunk-IRCVDFWG.js";
|
|
21
21
|
import {
|
|
22
22
|
trimTrailingSlash
|
|
23
23
|
} from "../../chunk-H37EB22A.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
FUNCTIONS_MOUNT_PREFIX,
|
|
29
29
|
assertFunctionName
|
|
30
30
|
} from "../../chunk-XQWJN6DC.js";
|
|
31
|
-
import "../../chunk-
|
|
31
|
+
import "../../chunk-OIRVEGPQ.js";
|
|
32
32
|
|
|
33
33
|
// src/stacks/supabase/handler.ts
|
|
34
34
|
function deriveResourcePath(options) {
|
|
@@ -129,7 +129,7 @@ function describeError(err) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// package.json
|
|
132
|
-
var version = "0.21.0-rc.
|
|
132
|
+
var version = "0.21.0-rc.2";
|
|
133
133
|
|
|
134
134
|
// src/metrics/otlp.ts
|
|
135
135
|
var SCOPE_NAME = "@lovable.dev/mcp-js";
|
|
@@ -416,14 +416,16 @@ function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
|
416
416
|
|
|
417
417
|
// src/auth/discovery.ts
|
|
418
418
|
var OAuthConfigurationError = class extends Error {
|
|
419
|
-
constructor(message) {
|
|
419
|
+
constructor(message, stage) {
|
|
420
420
|
super(message);
|
|
421
|
+
this.stage = stage;
|
|
421
422
|
this.name = "OAuthConfigurationError";
|
|
422
423
|
}
|
|
423
424
|
};
|
|
424
425
|
var OAuthUpstreamUnreachableError = class extends Error {
|
|
425
|
-
constructor(message) {
|
|
426
|
+
constructor(message, stage) {
|
|
426
427
|
super(message);
|
|
428
|
+
this.stage = stage;
|
|
427
429
|
this.name = "OAuthUpstreamUnreachableError";
|
|
428
430
|
}
|
|
429
431
|
};
|
|
@@ -457,32 +459,28 @@ function oauthMetadataUrlsForIssuer(issuer) {
|
|
|
457
459
|
return [...pathInsertedOAuthMetadataUrls(url, path), `${normalizedIssuer}/.well-known/openid-configuration`];
|
|
458
460
|
}
|
|
459
461
|
async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer) {
|
|
460
|
-
const
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
controller.abort();
|
|
470
|
-
return metadata;
|
|
471
|
-
} catch (aggregate) {
|
|
472
|
-
const causes = aggregate instanceof AggregateError ? aggregate.errors : [aggregate];
|
|
473
|
-
const unreachable = causes.some((c) => c instanceof MetadataUnreachableError);
|
|
474
|
-
const detail = causes.map((c) => c instanceof Error ? c.message : String(c)).join("; ");
|
|
475
|
-
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
476
|
-
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
477
|
-
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
462
|
+
const errors = [];
|
|
463
|
+
for (const url of metadataUrls) {
|
|
464
|
+
try {
|
|
465
|
+
return await fetchOAuthServerMetadata(url, expectedIssuer);
|
|
466
|
+
} catch (err) {
|
|
467
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
468
|
+
log.debug("oauth.discovery.attempt_failed", { url, ...describeError(error) });
|
|
469
|
+
errors.push(error);
|
|
470
|
+
}
|
|
478
471
|
}
|
|
472
|
+
const unreachable = errors.some((e) => e instanceof MetadataUnreachableError);
|
|
473
|
+
const detail = errors.map((e) => e.message).join("; ");
|
|
474
|
+
log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors: detail, unreachable });
|
|
475
|
+
const message = `failed to discover OAuth server metadata (${detail})`;
|
|
476
|
+
throw unreachable ? new MetadataUnreachableError(message) : new Error(message);
|
|
479
477
|
}
|
|
480
|
-
async function fetchOAuthServerMetadata(url, expectedIssuer
|
|
478
|
+
async function fetchOAuthServerMetadata(url, expectedIssuer) {
|
|
481
479
|
log.debug("oauth.discovery.fetch", { url });
|
|
482
480
|
let response;
|
|
483
481
|
try {
|
|
484
482
|
response = await fetch(url, {
|
|
485
|
-
signal: AbortSignal.
|
|
483
|
+
signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
|
|
486
484
|
redirect: "manual"
|
|
487
485
|
});
|
|
488
486
|
} catch (err) {
|
|
@@ -517,14 +515,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
|
|
|
517
515
|
...describeError(err),
|
|
518
516
|
outcome: "503 authorization server unreachable"
|
|
519
517
|
});
|
|
520
|
-
throw new OAuthUpstreamUnreachableError(message);
|
|
518
|
+
throw new OAuthUpstreamUnreachableError(message, "discovery");
|
|
521
519
|
}
|
|
522
520
|
log.error("oauth.discovery.config_error", {
|
|
523
521
|
issuer,
|
|
524
522
|
...describeError(err),
|
|
525
523
|
outcome: "500 oauth configuration error"
|
|
526
524
|
});
|
|
527
|
-
throw new OAuthConfigurationError(message);
|
|
525
|
+
throw new OAuthConfigurationError(message, "discovery");
|
|
528
526
|
}
|
|
529
527
|
}
|
|
530
528
|
function createOAuthDiscoveryResolver(auth) {
|
|
@@ -622,7 +620,10 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
622
620
|
response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
|
|
623
621
|
} catch (err) {
|
|
624
622
|
log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
|
|
625
|
-
throw new OAuthUpstreamUnreachableError(
|
|
623
|
+
throw new OAuthUpstreamUnreachableError(
|
|
624
|
+
`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
625
|
+
"jwks"
|
|
626
|
+
);
|
|
626
627
|
}
|
|
627
628
|
try {
|
|
628
629
|
if (!response.ok)
|
|
@@ -631,7 +632,7 @@ async function fetchVerificationKeySet(jwksUri) {
|
|
|
631
632
|
return (0, import_jose.createLocalJWKSet)(json);
|
|
632
633
|
} catch (err) {
|
|
633
634
|
log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
|
|
634
|
-
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}
|
|
635
|
+
throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
|
|
635
636
|
}
|
|
636
637
|
}
|
|
637
638
|
function assertAccessTokenTyp(token, allowed) {
|
|
@@ -844,21 +845,21 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
844
845
|
return { ok: true, auth };
|
|
845
846
|
} catch (err) {
|
|
846
847
|
if (err instanceof OAuthUpstreamUnreachableError) {
|
|
847
|
-
log.error("auth.upstream_unreachable", { ...describeError(err), outcome: "503" });
|
|
848
|
+
log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
|
|
848
849
|
await recorder?.emit({
|
|
849
850
|
tool: null,
|
|
850
851
|
method: "authorize",
|
|
851
|
-
outcome: "
|
|
852
|
+
outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
|
|
852
853
|
durationMs: nowMs() - startedAt
|
|
853
854
|
});
|
|
854
855
|
return { ok: false, response: oauthUpstreamUnreachableResponse() };
|
|
855
856
|
}
|
|
856
857
|
if (err instanceof OAuthConfigurationError) {
|
|
857
|
-
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
858
|
+
log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
|
|
858
859
|
await recorder?.emit({
|
|
859
860
|
tool: null,
|
|
860
861
|
method: "authorize",
|
|
861
|
-
outcome: "
|
|
862
|
+
outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
|
|
862
863
|
durationMs: nowMs() - startedAt
|
|
863
864
|
});
|
|
864
865
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
@@ -3,23 +3,23 @@ import {
|
|
|
3
3
|
} from "../../chunk-UQK5UO6C.js";
|
|
4
4
|
import {
|
|
5
5
|
createMcpProtocolHandler
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-4H3Y2KYT.js";
|
|
7
7
|
import {
|
|
8
8
|
createOAuthProtectedResourceMetadataHandler
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-7TVARTF4.js";
|
|
10
10
|
import {
|
|
11
11
|
createInvokeToolHandler
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-WOKM6B6H.js";
|
|
13
13
|
import {
|
|
14
14
|
createListToolsHandler
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-YE6N7XLA.js";
|
|
16
16
|
import "../../chunk-MA5H6PSF.js";
|
|
17
17
|
import {
|
|
18
18
|
createRecorderForRuntime
|
|
19
|
-
} from "../../chunk-
|
|
19
|
+
} from "../../chunk-IRCVDFWG.js";
|
|
20
20
|
import "../../chunk-H37EB22A.js";
|
|
21
21
|
import "../../chunk-6DXGZZA4.js";
|
|
22
|
-
import "../../chunk-
|
|
22
|
+
import "../../chunk-OIRVEGPQ.js";
|
|
23
23
|
|
|
24
24
|
// src/stacks/tanstack/handlers.ts
|
|
25
25
|
var STACK = "tanstack";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovable.dev/mcp-js",
|
|
3
|
-
"version": "0.21.0-rc.
|
|
3
|
+
"version": "0.21.0-rc.2",
|
|
4
4
|
"description": "Author MCP servers for Lovable apps. Declare tools with defineTool, register them in defineMcp, and a framework adapter (TanStack or Supabase Edge Functions) emits the route(s) at build time.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|