@lovable.dev/mcp-js 0.21.0-rc.3 → 0.21.0-rc.4

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 (39) hide show
  1. package/README.md +2 -1
  2. package/dist/{base-DTtaX5Rf.d.ts → base-CFy5vZ5Z.d.ts} +7 -2
  3. package/dist/{chunk-SIDWSSWV.js → chunk-2PJKJI76.js} +1 -1
  4. package/dist/chunk-6QFZYYUV.js +11 -0
  5. package/dist/{chunk-TVU5FL2T.js → chunk-7G743K3G.js} +1 -1
  6. package/dist/{chunk-JIOOUIDX.js → chunk-FBR7D3XV.js} +6 -2
  7. package/dist/{chunk-5W6JK6OS.js → chunk-PML3SKRA.js} +6 -2
  8. package/dist/{chunk-CIAVINZ5.js → chunk-Q22Z6G6N.js} +45 -80
  9. package/dist/{chunk-NENAFXZJ.js → chunk-XPYU4DI6.js} +1 -1
  10. package/dist/cli/extract-manifest.cjs +3 -1
  11. package/dist/cli/extract-manifest.js +5 -3
  12. package/dist/index.cjs +12 -0
  13. package/dist/index.d.cts +3 -2
  14. package/dist/index.d.ts +3 -2
  15. package/dist/index.js +11 -1
  16. package/dist/protocols/mcp/index.cjs +52 -79
  17. package/dist/protocols/mcp/index.d.cts +2 -2
  18. package/dist/protocols/mcp/index.d.ts +2 -2
  19. package/dist/protocols/mcp/index.js +4 -3
  20. package/dist/protocols/oauth-metadata.cjs +40 -60
  21. package/dist/protocols/oauth-metadata.d.cts +1 -1
  22. package/dist/protocols/oauth-metadata.d.ts +1 -1
  23. package/dist/protocols/oauth-metadata.js +3 -3
  24. package/dist/protocols/rest/index.cjs +52 -79
  25. package/dist/protocols/rest/index.d.cts +2 -2
  26. package/dist/protocols/rest/index.d.ts +2 -2
  27. package/dist/protocols/rest/index.js +5 -4
  28. package/dist/stacks/supabase/index.cjs +57 -82
  29. package/dist/stacks/supabase/index.d.cts +1 -1
  30. package/dist/stacks/supabase/index.d.ts +1 -1
  31. package/dist/stacks/supabase/index.js +7 -6
  32. package/dist/stacks/supabase/vite.cjs +1 -1
  33. package/dist/stacks/supabase/vite.js +1 -1
  34. package/dist/stacks/tanstack/index.cjs +57 -82
  35. package/dist/stacks/tanstack/index.d.cts +1 -1
  36. package/dist/stacks/tanstack/index.d.ts +1 -1
  37. package/dist/stacks/tanstack/index.js +7 -6
  38. package/dist/{types-CPkhCRxc.d.ts → types-qqrmJ736.d.ts} +10 -0
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -179,7 +179,8 @@ Use an OAuth access token from the configured authorization server for MCP calls
179
179
  | --- | --- |
180
180
  | `issuer` | OAuth/OIDC issuer URL. Must be HTTPS except localhost development URLs and must match the token `iss` exactly. Required. |
181
181
  | `resource` | Canonical protected-resource URL published in metadata. It also anchors the accepted audience unless `acceptedAudiences` is set. When omitted, the published resource is derived from the request origin plus the stack adapter's `resourcePath` and you must set `acceptedAudiences`; the metadata handler throws at construction if neither `resource` nor `resourcePath` is set. |
182
- | `acceptedAudiences` | Accepted JWT audience(s). Defaults to `resource` when that is set. One of `resource` or `acceptedAudiences` is required. |
182
+ | `acceptedAudiences` | Accepted JWT audience(s). Defaults to `resource` when that is set. One of `resource` or `acceptedAudiences` is required. A populated token `aud` must match one of these exactly; when `aud` is empty or absent, see `acceptResourceClaim`. |
183
+ | `acceptResourceClaim` | Defaults to `true`: a token whose `aud` is an empty array or absent is accepted when its `resource` claim matches an accepted audience (trailing slashes ignored). The fallback engages for **any** configured issuer minting such tokens, not only Lovable's. The `resource` claim is a Lovable OAuth convention derived from the RFC 8707 `resource` request parameter, not a registered JWT claim; Lovable's OAuth server validates the requested resource at authorization time before stamping it. A populated `aud` is always authoritative — the fallback never rescues a non-matching `aud`. Set `false` to require a matching `aud` (strict RFC 9068). |
183
184
  | `jwksUri` | JWKS URL override. If omitted, the runtime discovers `jwks_uri` from OAuth/OIDC metadata; setting it skips discovery entirely. |
184
185
  | `requiredScopes` | Required scopes. Advertised in metadata/challenges and enforced against the token `scope`. |
185
186
  | `requireOAuthClientClaim` | Defaults to `true`; rejects tokens carrying neither `client_id` nor the OIDC `azp` (authorized party) so copied app-session JWTs do not pass as OAuth client tokens. Supabase OAuth 2.1 server tokens carry `client_id` and issuers like Google/Keycloak/Entra use `azp`, so keep the default; only legacy `signInWithPassword` session tokens lack both and need `false`. |
@@ -1,6 +1,8 @@
1
- type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_discovery_config_error" | "auth_discovery_unreachable" | "auth_jwks_config_error" | "auth_jwks_unreachable";
1
+ type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_config_error";
2
2
  /** One recorded MCP call. Carries no arguments or response payloads — only the
3
- * tool name, the JSON-RPC method, the result class, timing, and byte sizes. */
3
+ * tool name, the JSON-RPC method, the result class, timing, and byte sizes.
4
+ * `errorText` is the sole exception: it is logged locally for debugging and
5
+ * deliberately never included in the OTLP payload (see `emit` / `buildLogsPayload`). */
4
6
  interface InvocationRecord {
5
7
  /** Tool name for `tools/call`; `null` for list/initialize, transport faults, and auth-config failures. */
6
8
  tool: string | null;
@@ -10,6 +12,9 @@ interface InvocationRecord {
10
12
  durationMs: number;
11
13
  reqBytes?: number;
12
14
  resBytes?: number;
15
+ /** The `tool_error` message (text content of an `isError` result). Local log
16
+ * only — never sent to the collector, so it stays on-box for the operator. */
17
+ errorText?: string;
13
18
  }
14
19
  /** A per-request telemetry recorder. `emit` logs the invocation and sends it as a
15
20
  * single OTLP POST, awaited so it lands before the request ends. */
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.21.0-rc.3";
2
+ var version = "0.21.0-rc.4";
3
3
 
4
4
  export {
5
5
  version
@@ -0,0 +1,11 @@
1
+ // src/core/content.ts
2
+ function extractTextContent(content) {
3
+ if (!content)
4
+ return void 0;
5
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
6
+ return text.length > 0 ? text : void 0;
7
+ }
8
+
9
+ export {
10
+ extractTextContent
11
+ };
@@ -6,7 +6,7 @@ import {
6
6
  headResponse,
7
7
  methodNotAllowed,
8
8
  withCors
9
- } from "./chunk-CIAVINZ5.js";
9
+ } from "./chunk-Q22Z6G6N.js";
10
10
 
11
11
  // src/protocols/rest/list-tools.ts
12
12
  import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -1,3 +1,6 @@
1
+ import {
2
+ extractTextContent
3
+ } from "./chunk-6QFZYYUV.js";
1
4
  import {
2
5
  ToolContext
3
6
  } from "./chunk-MA5H6PSF.js";
@@ -10,7 +13,7 @@ import {
10
13
  methodNotAllowed,
11
14
  nowMs,
12
15
  withCors
13
- } from "./chunk-CIAVINZ5.js";
16
+ } from "./chunk-Q22Z6G6N.js";
14
17
 
15
18
  // src/protocols/rest/invoke-tool.ts
16
19
  import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -113,7 +116,8 @@ function createInvokeToolHandler(mcp, options = {}) {
113
116
  tool: tool.name,
114
117
  method: "tools/call",
115
118
  outcome: result.isError ? "tool_error" : "ok",
116
- durationMs: nowMs() - start
119
+ durationMs: nowMs() - start,
120
+ errorText: result.isError ? extractTextContent(result.content) : void 0
117
121
  });
118
122
  return Response.json({
119
123
  content: result.content ?? [],
@@ -1,3 +1,6 @@
1
+ import {
2
+ extractTextContent
3
+ } from "./chunk-6QFZYYUV.js";
1
4
  import {
2
5
  ToolContext
3
6
  } from "./chunk-MA5H6PSF.js";
@@ -7,7 +10,7 @@ import {
7
10
  createRequestAuthorizer,
8
11
  nowMs,
9
12
  withCors
10
- } from "./chunk-CIAVINZ5.js";
13
+ } from "./chunk-Q22Z6G6N.js";
11
14
  import {
12
15
  describeError,
13
16
  log
@@ -45,7 +48,8 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
45
48
  tool: tool.name,
46
49
  method: "tools/call",
47
50
  outcome: result.isError ? "tool_error" : "ok",
48
- durationMs: nowMs() - start
51
+ durationMs: nowMs() - start,
52
+ errorText: result.isError ? extractTextContent(result.content) : void 0
49
53
  });
50
54
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
51
55
  };
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-6DXGZZA4.js";
14
14
  import {
15
15
  version
16
- } from "./chunk-SIDWSSWV.js";
16
+ } from "./chunk-2PJKJI76.js";
17
17
 
18
18
  // src/core/http.ts
19
19
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -156,7 +156,8 @@ var BaseMetricRecorder = class {
156
156
  method: ev.method,
157
157
  outcome: ev.outcome,
158
158
  durationMs: ev.durationMs,
159
- stack: this.stack
159
+ stack: this.stack,
160
+ ...ev.errorText !== void 0 && { errorText: ev.errorText }
160
161
  });
161
162
  if (!this.config.enabled)
162
163
  return;
@@ -284,23 +285,9 @@ function cachedPromise(load, label) {
284
285
 
285
286
  // src/auth/discovery.ts
286
287
  var OAuthConfigurationError = class extends Error {
287
- constructor(message, stage) {
288
- super(message);
289
- this.stage = stage;
290
- this.name = "OAuthConfigurationError";
291
- }
292
- };
293
- var OAuthUpstreamUnreachableError = class extends Error {
294
- constructor(message, stage) {
295
- super(message);
296
- this.stage = stage;
297
- this.name = "OAuthUpstreamUnreachableError";
298
- }
299
- };
300
- var MetadataUnreachableError = class extends Error {
301
288
  constructor(message) {
302
289
  super(message);
303
- this.name = "MetadataUnreachableError";
290
+ this.name = "OAuthConfigurationError";
304
291
  }
305
292
  };
306
293
  var METADATA_FETCH_TIMEOUT_MS = 5e3;
@@ -332,28 +319,16 @@ async function fetchFirstValidOAuthServerMetadata(metadataUrls, expectedIssuer)
332
319
  try {
333
320
  return await fetchOAuthServerMetadata(url, expectedIssuer);
334
321
  } 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);
322
+ log.debug("oauth.discovery.attempt_failed", { url, ...describeError(err) });
323
+ errors.push(`${url}: ${err instanceof Error ? err.message : String(err)}`);
338
324
  }
339
325
  }
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);
326
+ log.error("oauth.discovery.exhausted", { expectedIssuer, urlsTried: metadataUrls, errors });
327
+ throw new Error(`failed to discover OAuth server metadata (${errors.join("; ")})`);
345
328
  }
346
329
  async function fetchOAuthServerMetadata(url, expectedIssuer) {
347
330
  log.debug("oauth.discovery.fetch", { url });
348
- let response;
349
- try {
350
- response = await fetch(url, {
351
- signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS),
352
- redirect: "manual"
353
- });
354
- } catch (err) {
355
- throw new MetadataUnreachableError(err instanceof Error ? err.message : String(err));
356
- }
331
+ const response = await fetch(url, { signal: AbortSignal.timeout(METADATA_FETCH_TIMEOUT_MS), redirect: "manual" });
357
332
  if (!response.ok) {
358
333
  throw new Error(String(response.status));
359
334
  }
@@ -376,21 +351,14 @@ async function fetchIssuerOAuthServerMetadata(issuer) {
376
351
  try {
377
352
  return await fetchFirstValidOAuthServerMetadata(oauthMetadataUrlsForIssuer(issuer), issuer);
378
353
  } catch (err) {
379
- const message = `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`;
380
- if (err instanceof MetadataUnreachableError) {
381
- log.error("oauth.discovery.unreachable", {
382
- issuer,
383
- ...describeError(err),
384
- outcome: "503 authorization server unreachable"
385
- });
386
- throw new OAuthUpstreamUnreachableError(message, "discovery");
387
- }
388
354
  log.error("oauth.discovery.config_error", {
389
355
  issuer,
390
356
  ...describeError(err),
391
357
  outcome: "500 oauth configuration error"
392
358
  });
393
- throw new OAuthConfigurationError(message, "discovery");
359
+ throw new OAuthConfigurationError(
360
+ `OAuth issuer discovery failed: ${err instanceof Error ? err.message : String(err)}`
361
+ );
394
362
  }
395
363
  }
396
364
  function createOAuthDiscoveryResolver(auth) {
@@ -423,13 +391,18 @@ function readString(value) {
423
391
  function splitScopes(value) {
424
392
  if (typeof value === "string")
425
393
  return value.split(/\s+/).filter(Boolean);
426
- if (Array.isArray(value))
427
- return value.filter((entry) => typeof entry === "string" && entry.length > 0);
428
- return [];
394
+ return stringClaimList(value);
429
395
  }
430
396
  function stringClaim(claims, name) {
431
397
  return readString(claims[name]);
432
398
  }
399
+ function stringClaimList(value) {
400
+ if (typeof value === "string")
401
+ return value === "" ? [] : [value];
402
+ if (Array.isArray(value))
403
+ return value.filter((entry) => typeof entry === "string" && entry !== "");
404
+ return [];
405
+ }
433
406
 
434
407
  // src/auth/verifier.ts
435
408
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
@@ -456,24 +429,15 @@ function tokenHeaderFields(token) {
456
429
  }
457
430
  }
458
431
  async function fetchVerificationKeySet(jwksUri) {
459
- let response;
460
- try {
461
- response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
462
- } catch (err) {
463
- log.error("oauth.jwks.unreachable", { ...describeError(err), outcome: "503 authorization server unreachable" });
464
- throw new OAuthUpstreamUnreachableError(
465
- `JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`,
466
- "jwks"
467
- );
468
- }
469
432
  try {
433
+ const response = await fetch(jwksUri, { signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS), redirect: "manual" });
470
434
  if (!response.ok)
471
435
  throw new Error(`JWKS endpoint returned ${response.status}`);
472
436
  const json = await response.json();
473
437
  return createLocalJWKSet(json);
474
438
  } catch (err) {
475
439
  log.error("oauth.jwks.fetch_failed", { ...describeError(err), outcome: "500 oauth configuration error" });
476
- throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`, "jwks");
440
+ throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
477
441
  }
478
442
  }
479
443
  function assertAccessTokenTyp(token, allowed) {
@@ -490,13 +454,12 @@ function assertAccessTokenTyp(token, allowed) {
490
454
  throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
491
455
  }
492
456
  }
493
- async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
457
+ async function verifyJwtClaims(token, keySet, issuer, auth) {
494
458
  try {
495
459
  const { payload } = await jwtVerify(token, keySet, {
496
460
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
497
461
  // `iss` carries the slash the AS publishes still verifies.
498
462
  issuer: [issuer, `${issuer}/`],
499
- audience: [...audience],
500
463
  algorithms: auth.algorithms ? [...auth.algorithms] : DEFAULT_JWT_ALGORITHMS,
501
464
  requiredClaims: ["sub", "exp"],
502
465
  clockTolerance: auth.clockToleranceSeconds ?? DEFAULT_CLOCK_TOLERANCE_SECONDS
@@ -507,6 +470,22 @@ async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
507
470
  throw err;
508
471
  }
509
472
  }
473
+ function checkAcceptedAudience(claims, accepted, auth) {
474
+ const audPopulated = claims.aud !== void 0 && !(Array.isArray(claims.aud) && claims.aud.length === 0);
475
+ if (audPopulated) {
476
+ if (stringClaimList(claims.aud).some((audience) => accepted.includes(audience)))
477
+ return "aud";
478
+ log.debug("oauth.verify.bad_audience", { tokenAud: claims.aud, accepted, outcome: "401 invalid_token" });
479
+ } else if (auth.acceptResourceClaim !== false) {
480
+ const acceptedTrimmed = accepted.map(trimTrailingSlash);
481
+ if (stringClaimList(claims.resource).some((resource) => acceptedTrimmed.includes(trimTrailingSlash(resource))))
482
+ return "resource";
483
+ log.debug("oauth.verify.bad_resource", { tokenResource: claims.resource, accepted, outcome: "401 invalid_token" });
484
+ } else {
485
+ log.debug("oauth.verify.empty_audience", { accepted, outcome: "401 invalid_token" });
486
+ }
487
+ throw new OAuthTokenError(401, "invalid_token", "token audience is not accepted");
488
+ }
510
489
  function assertNonEmptySubject(claims) {
511
490
  const sub = claims["sub"];
512
491
  if (typeof sub !== "string" || sub.trim() === "") {
@@ -551,14 +530,16 @@ function createOAuthTokenVerifier(auth, discovery) {
551
530
  log.debug("oauth.jwks.fetch", { jwksUri });
552
531
  const keySet = await fetchVerificationKeySet(jwksUri);
553
532
  assertAccessTokenTyp(token, allowedTyps);
554
- const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
533
+ const claims = await verifyJwtClaims(token, keySet, issuer, auth);
534
+ const audienceVia = checkAcceptedAudience(claims, acceptedAudiences, auth);
555
535
  assertNonEmptySubject(claims);
556
536
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
557
537
  assertOAuthClientClaim(auth, context.principal.clientId);
558
538
  log.info("oauth.verify.ok", {
559
539
  sub: context.principal.sub,
560
540
  clientId: context.principal.clientId,
561
- scopes: context.principal.scopes
541
+ scopes: context.principal.scopes,
542
+ audienceVia
562
543
  });
563
544
  return context;
564
545
  };
@@ -607,12 +588,6 @@ function oauthConfigurationErrorResponse() {
607
588
  headers: { ...JSON_HEADERS, "Cache-Control": "no-store" }
608
589
  });
609
590
  }
610
- function oauthUpstreamUnreachableResponse() {
611
- return new Response(JSON.stringify({ error: "authorization server unreachable" }), {
612
- status: 503,
613
- headers: { ...JSON_HEADERS, "Cache-Control": "no-store", "Retry-After": "30" }
614
- });
615
- }
616
591
  function parseBearerToken(request) {
617
592
  const header = request.headers.get("Authorization");
618
593
  if (!header)
@@ -685,22 +660,12 @@ function createRequestAuthorizer(mcp, options = {}) {
685
660
  assertRequiredScopes(runtime.auth, auth);
686
661
  return { ok: true, auth };
687
662
  } catch (err) {
688
- if (err instanceof OAuthUpstreamUnreachableError) {
689
- log.error("auth.upstream_unreachable", { ...describeError(err), stage: err.stage, outcome: "503" });
690
- await recorder?.emit({
691
- tool: null,
692
- method: "authorize",
693
- outcome: err.stage === "jwks" ? "auth_jwks_unreachable" : "auth_discovery_unreachable",
694
- durationMs: nowMs() - startedAt
695
- });
696
- return { ok: false, response: oauthUpstreamUnreachableResponse() };
697
- }
698
663
  if (err instanceof OAuthConfigurationError) {
699
- log.error("auth.config_error", { ...describeError(err), stage: err.stage, outcome: "500" });
664
+ log.error("auth.config_error", { ...describeError(err), outcome: "500" });
700
665
  await recorder?.emit({
701
666
  tool: null,
702
667
  method: "authorize",
703
- outcome: err.stage === "jwks" ? "auth_jwks_config_error" : "auth_discovery_config_error",
668
+ outcome: "auth_config_error",
704
669
  durationMs: nowMs() - startedAt
705
670
  });
706
671
  return { ok: false, response: oauthConfigurationErrorResponse() };
@@ -7,7 +7,7 @@ import {
7
7
  oauthConfigurationErrorResponse,
8
8
  resolveProtectedResource,
9
9
  withCors
10
- } from "./chunk-CIAVINZ5.js";
10
+ } from "./chunk-Q22Z6G6N.js";
11
11
  import {
12
12
  describeError,
13
13
  log
@@ -13,7 +13,7 @@ function isFileMissing(err) {
13
13
  }
14
14
 
15
15
  // package.json
16
- var version = "0.21.0-rc.3";
16
+ var version = "0.21.0-rc.4";
17
17
 
18
18
  // src/protocols/rest/list-tools.ts
19
19
  var import_zod_compat = require("@modelcontextprotocol/sdk/server/zod-compat.js");
@@ -80,6 +80,8 @@ function manifestAuth(auth) {
80
80
  oauth.protected_resource_metadata_url = auth.protectedResourceMetadataUrl;
81
81
  if (auth.requireOAuthClientClaim !== void 0)
82
82
  oauth.require_oauth_client_claim = auth.requireOAuthClientClaim;
83
+ if (auth.acceptResourceClaim !== void 0)
84
+ oauth.accept_resource_claim = auth.acceptResourceClaim;
83
85
  if (auth.acceptedAudiences !== void 0)
84
86
  oauth.accepted_audiences = auth.acceptedAudiences;
85
87
  if (auth.requiredScopes !== void 0)
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildMcpListing
4
- } from "../chunk-TVU5FL2T.js";
5
- import "../chunk-CIAVINZ5.js";
4
+ } from "../chunk-7G743K3G.js";
5
+ import "../chunk-Q22Z6G6N.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-SIDWSSWV.js";
13
+ } from "../chunk-2PJKJI76.js";
14
14
 
15
15
  // src/manifest/io.ts
16
16
  import { randomUUID } from "crypto";
@@ -35,6 +35,8 @@ function manifestAuth(auth) {
35
35
  oauth.protected_resource_metadata_url = auth.protectedResourceMetadataUrl;
36
36
  if (auth.requireOAuthClientClaim !== void 0)
37
37
  oauth.require_oauth_client_claim = auth.requireOAuthClientClaim;
38
+ if (auth.acceptResourceClaim !== void 0)
39
+ oauth.accept_resource_claim = auth.acceptResourceClaim;
38
40
  if (auth.acceptedAudiences !== void 0)
39
41
  oauth.accepted_audiences = auth.acceptedAudiences;
40
42
  if (auth.requiredScopes !== void 0)
package/dist/index.cjs CHANGED
@@ -55,6 +55,9 @@ function resolveMetricsConfig(config = true) {
55
55
  }
56
56
 
57
57
  // src/core/url.ts
58
+ function trimTrailingSlash(value) {
59
+ return value.replace(/\/+$/, "");
60
+ }
58
61
  function isLocalHTTPHost(hostname) {
59
62
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
60
63
  }
@@ -166,8 +169,17 @@ function assertOAuthConfig(auth2) {
166
169
  throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
167
170
  }
168
171
  assertNonEmptyString("auth.acceptedAudiences", audience);
172
+ if (trimTrailingSlash(audience) === "") {
173
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
174
+ }
169
175
  }
170
176
  }
177
+ if (auth2.requireOAuthClientClaim !== void 0 && typeof auth2.requireOAuthClientClaim !== "boolean") {
178
+ throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
179
+ }
180
+ if (auth2.acceptResourceClaim !== void 0 && typeof auth2.acceptResourceClaim !== "boolean") {
181
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
182
+ }
171
183
  if (auth2.requiredScopes !== void 0) {
172
184
  if (!Array.isArray(auth2.requiredScopes)) {
173
185
  throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, l as ToolDefinition, M as McpAuthConfig } from './types-CPkhCRxc.js';
2
- export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, f as MetricsConfig, g as MetricsOptions, R as ResourceLink, h as ResourceLinkIcon, T as TextContent, i as ToolAnnotations, j as ToolContent, k as ToolContext, m as ToolHandlerResult, n as ZodSchema } from './types-CPkhCRxc.js';
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, l as ToolDefinition, M as McpAuthConfig } from './types-qqrmJ736.js';
2
+ export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, f as MetricsConfig, g as MetricsOptions, R as ResourceLink, h as ResourceLinkIcon, T as TextContent, i as ToolAnnotations, j as ToolContent, k as ToolContext, m as ToolHandlerResult, n as ZodSchema } from './types-qqrmJ736.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -24,6 +24,7 @@ interface IssuerOAuthOptionsBase {
24
24
  readonly resourceDocumentation?: string;
25
25
  readonly protectedResourceMetadataUrl?: string;
26
26
  readonly requireOAuthClientClaim?: boolean;
27
+ readonly acceptResourceClaim?: boolean;
27
28
  readonly issuer: string;
28
29
  readonly requiredScopes?: readonly string[];
29
30
  readonly jwksUri?: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, l as ToolDefinition, M as McpAuthConfig } from './types-CPkhCRxc.js';
2
- export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, f as MetricsConfig, g as MetricsOptions, R as ResourceLink, h as ResourceLinkIcon, T as TextContent, i as ToolAnnotations, j as ToolContent, k as ToolContext, m as ToolHandlerResult, n as ZodSchema } from './types-CPkhCRxc.js';
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, l as ToolDefinition, M as McpAuthConfig } from './types-qqrmJ736.js';
2
+ export { A as AudioContent, C as ContentAnnotations, a as ContentBlock, E as EmbeddedBlobResource, b as EmbeddedResource, c as EmbeddedTextResource, I as ImageContent, J as JwtClaims, f as MetricsConfig, g as MetricsOptions, R as ResourceLink, h as ResourceLinkIcon, T as TextContent, i as ToolAnnotations, j as ToolContent, k as ToolContext, m as ToolHandlerResult, n as ZodSchema } from './types-qqrmJ736.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -24,6 +24,7 @@ interface IssuerOAuthOptionsBase {
24
24
  readonly resourceDocumentation?: string;
25
25
  readonly protectedResourceMetadataUrl?: string;
26
26
  readonly requireOAuthClientClaim?: boolean;
27
+ readonly acceptResourceClaim?: boolean;
27
28
  readonly issuer: string;
28
29
  readonly requiredScopes?: readonly string[];
29
30
  readonly jwksUri?: string;
package/dist/index.js CHANGED
@@ -4,7 +4,8 @@ import {
4
4
  import {
5
5
  parseSafeUrl,
6
6
  resolveMetricsConfig,
7
- setLogLevel
7
+ setLogLevel,
8
+ trimTrailingSlash
8
9
  } from "./chunk-H37EB22A.js";
9
10
 
10
11
  // src/core/define.ts
@@ -86,8 +87,17 @@ function assertOAuthConfig(auth2) {
86
87
  throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
87
88
  }
88
89
  assertNonEmptyString("auth.acceptedAudiences", audience);
90
+ if (trimTrailingSlash(audience) === "") {
91
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
92
+ }
89
93
  }
90
94
  }
95
+ if (auth2.requireOAuthClientClaim !== void 0 && typeof auth2.requireOAuthClientClaim !== "boolean") {
96
+ throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
97
+ }
98
+ if (auth2.acceptResourceClaim !== void 0 && typeof auth2.acceptResourceClaim !== "boolean") {
99
+ throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
100
+ }
91
101
  if (auth2.requiredScopes !== void 0) {
92
102
  if (!Array.isArray(auth2.requiredScopes)) {
93
103
  throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);