@lovable.dev/mcp-js 0.10.0 → 0.11.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 (36) hide show
  1. package/dist/{chunk-4XJ2R3DD.js → chunk-ENWRS6AT.js} +1 -1
  2. package/dist/{chunk-LAFJDJRY.js → chunk-G4XA7IJM.js} +17 -1
  3. package/dist/{chunk-X7V2CL7C.js → chunk-QDKOF4UF.js} +1 -1
  4. package/dist/{chunk-PJXKJNSZ.js → chunk-VNRQPA4K.js} +1 -1
  5. package/dist/{chunk-DF3DD3KD.js → chunk-WLNT2FX7.js} +1 -1
  6. package/dist/{chunk-SZLSAGDF.js → chunk-YWLMMDET.js} +1 -1
  7. package/dist/cli/extract-manifest.cjs +1 -1
  8. package/dist/cli/extract-manifest.js +3 -3
  9. package/dist/index.cjs +18 -1
  10. package/dist/index.d.cts +3 -2
  11. package/dist/index.d.ts +3 -2
  12. package/dist/index.js +18 -1
  13. package/dist/protocols/mcp/index.cjs +17 -1
  14. package/dist/protocols/mcp/index.d.cts +1 -1
  15. package/dist/protocols/mcp/index.d.ts +1 -1
  16. package/dist/protocols/mcp/index.js +2 -2
  17. package/dist/protocols/oauth-metadata.cjs +17 -1
  18. package/dist/protocols/oauth-metadata.d.cts +1 -1
  19. package/dist/protocols/oauth-metadata.d.ts +1 -1
  20. package/dist/protocols/oauth-metadata.js +2 -2
  21. package/dist/protocols/rest/index.cjs +17 -1
  22. package/dist/protocols/rest/index.d.cts +1 -1
  23. package/dist/protocols/rest/index.d.ts +1 -1
  24. package/dist/protocols/rest/index.js +3 -3
  25. package/dist/stacks/supabase/index.cjs +33 -6
  26. package/dist/stacks/supabase/index.d.cts +1 -1
  27. package/dist/stacks/supabase/index.d.ts +1 -1
  28. package/dist/stacks/supabase/index.js +21 -10
  29. package/dist/stacks/supabase/vite.cjs +1 -1
  30. package/dist/stacks/supabase/vite.js +1 -1
  31. package/dist/stacks/tanstack/index.cjs +17 -1
  32. package/dist/stacks/tanstack/index.d.cts +1 -1
  33. package/dist/stacks/tanstack/index.d.ts +1 -1
  34. package/dist/stacks/tanstack/index.js +5 -5
  35. package/dist/{types-C5SSORxe.d.ts → types-BanzncFh.d.ts} +8 -0
  36. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.10.0";
2
+ var version = "0.11.0";
3
3
 
4
4
  export {
5
5
  version
@@ -190,6 +190,7 @@ function stringClaim(claims, name) {
190
190
  // src/auth/verifier.ts
191
191
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
192
192
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
193
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
193
194
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
194
195
  var OAuthTokenError = class extends Error {
195
196
  constructor(status, oauthError, message) {
@@ -222,10 +223,23 @@ async function fetchVerificationKeySet(jwksUri) {
222
223
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
223
224
  }
224
225
  }
226
+ function assertAccessTokenTyp(token, allowed) {
227
+ let header;
228
+ try {
229
+ header = decodeProtectedHeader(token);
230
+ } catch (err) {
231
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
232
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
233
+ }
234
+ const typ = header.typ;
235
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
236
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
237
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
238
+ }
239
+ }
225
240
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
226
241
  try {
227
242
  const { payload } = await jwtVerify(token, keySet, {
228
- typ: "at+jwt",
229
243
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
230
244
  // `iss` carries the slash the AS publishes still verifies.
231
245
  issuer: [issuer, `${issuer}/`],
@@ -274,6 +288,7 @@ function buildMcpAuthContext(args) {
274
288
  };
275
289
  }
276
290
  function createOAuthTokenVerifier(auth, discovery) {
291
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
277
292
  return async (token, request, options) => {
278
293
  const resource = resolveProtectedResource(auth, request, options);
279
294
  const issuer = await discovery.resolveIssuer();
@@ -282,6 +297,7 @@ function createOAuthTokenVerifier(auth, discovery) {
282
297
  const jwksUri = await discovery.resolveJwksUri();
283
298
  log.debug("oauth.jwks.fetch", { jwksUri });
284
299
  const keySet = await fetchVerificationKeySet(jwksUri);
300
+ assertAccessTokenTyp(token, allowedTyps);
285
301
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
286
302
  assertNonEmptySubject(claims);
287
303
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -7,7 +7,7 @@ import {
7
7
  oauthConfigurationErrorResponse,
8
8
  resolveProtectedResource,
9
9
  withCors
10
- } from "./chunk-LAFJDJRY.js";
10
+ } from "./chunk-G4XA7IJM.js";
11
11
  import {
12
12
  describeError,
13
13
  log
@@ -5,7 +5,7 @@ import {
5
5
  headResponse,
6
6
  methodNotAllowed,
7
7
  withCors
8
- } from "./chunk-LAFJDJRY.js";
8
+ } from "./chunk-G4XA7IJM.js";
9
9
 
10
10
  // src/protocols/rest/list-tools.ts
11
11
  import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -5,7 +5,7 @@ import {
5
5
  corsPreflightResponse,
6
6
  createRequestAuthorizer,
7
7
  withCors
8
- } from "./chunk-LAFJDJRY.js";
8
+ } from "./chunk-G4XA7IJM.js";
9
9
  import {
10
10
  describeError,
11
11
  log
@@ -8,7 +8,7 @@ import {
8
8
  createRequestAuthorizer,
9
9
  methodNotAllowed,
10
10
  withCors
11
- } from "./chunk-LAFJDJRY.js";
11
+ } from "./chunk-G4XA7IJM.js";
12
12
 
13
13
  // src/protocols/rest/invoke-tool.ts
14
14
  import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -13,7 +13,7 @@ function isFileMissing(err) {
13
13
  }
14
14
 
15
15
  // package.json
16
- var version = "0.10.0";
16
+ var version = "0.11.0";
17
17
 
18
18
  // src/protocols/rest/list-tools.ts
19
19
  var import_zod_compat = require("@modelcontextprotocol/sdk/server/zod-compat.js");
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildMcpListing
4
- } from "../chunk-PJXKJNSZ.js";
5
- import "../chunk-LAFJDJRY.js";
4
+ } from "../chunk-VNRQPA4K.js";
5
+ import "../chunk-G4XA7IJM.js";
6
6
  import "../chunk-QC3DXQTH.js";
7
7
  import "../chunk-6DXGZZA4.js";
8
8
  import {
9
9
  version
10
- } from "../chunk-4XJ2R3DD.js";
10
+ } from "../chunk-ENWRS6AT.js";
11
11
  import {
12
12
  isFileMissing
13
13
  } from "../chunk-Y3ZFPEQH.js";
package/dist/index.cjs CHANGED
@@ -159,6 +159,20 @@ function assertOAuthConfig(auth2) {
159
159
  for (const algorithm of auth2.algorithms)
160
160
  assertJwtAlgorithm(algorithm);
161
161
  }
162
+ if (auth2.accessTokenTyp !== void 0) {
163
+ if (!Array.isArray(auth2.accessTokenTyp)) {
164
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
165
+ }
166
+ if (auth2.accessTokenTyp.length === 0) {
167
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
168
+ }
169
+ for (const typ of auth2.accessTokenTyp) {
170
+ if (typeof typ !== "string") {
171
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
172
+ }
173
+ assertNonEmptyString("auth.accessTokenTyp", typ);
174
+ }
175
+ }
162
176
  if (auth2.clockToleranceSeconds !== void 0)
163
177
  assertClockToleranceSeconds(auth2.clockToleranceSeconds);
164
178
  if (auth2.resource === void 0 && auth2.acceptedAudiences === void 0) {
@@ -174,6 +188,8 @@ function freezeAuth(auth2) {
174
188
  Object.freeze(auth2.requiredScopes);
175
189
  if (auth2.algorithms)
176
190
  Object.freeze(auth2.algorithms);
191
+ if (auth2.accessTokenTyp)
192
+ Object.freeze(auth2.accessTokenTyp);
177
193
  Object.freeze(auth2);
178
194
  }
179
195
  function defineTool(def) {
@@ -214,7 +230,8 @@ function issuer(options) {
214
230
  ...options,
215
231
  acceptedAudiences: frozenAudiences(options.acceptedAudiences),
216
232
  requiredScopes: frozenArray(options.requiredScopes),
217
- algorithms: frozenArray(options.algorithms)
233
+ algorithms: frozenArray(options.algorithms),
234
+ accessTokenTyp: frozenArray(options.accessTokenTyp)
218
235
  })
219
236
  );
220
237
  }
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-C5SSORxe.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, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-C5SSORxe.js';
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-BanzncFh.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, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -29,6 +29,7 @@ interface IssuerOAuthOptionsBase {
29
29
  readonly jwksUri?: string;
30
30
  readonly algorithms?: readonly string[];
31
31
  readonly clockToleranceSeconds?: number;
32
+ readonly accessTokenTyp?: readonly string[];
32
33
  }
33
34
  type IssuerOAuthOptions = IssuerOAuthOptionsBase & ({
34
35
  readonly resource: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-C5SSORxe.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, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-C5SSORxe.js';
1
+ import { e as McpDefinitionInput, d as McpDefinition, Z as ZodRawShape, j as ToolDefinition, M as McpAuthConfig } from './types-BanzncFh.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, R as ResourceLink, f as ResourceLinkIcon, T as TextContent, g as ToolAnnotations, h as ToolContent, i as ToolContext, k as ToolHandlerResult, l as ZodSchema } from './types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -29,6 +29,7 @@ interface IssuerOAuthOptionsBase {
29
29
  readonly jwksUri?: string;
30
30
  readonly algorithms?: readonly string[];
31
31
  readonly clockToleranceSeconds?: number;
32
+ readonly accessTokenTyp?: readonly string[];
32
33
  }
33
34
  type IssuerOAuthOptions = IssuerOAuthOptionsBase & ({
34
35
  readonly resource: string;
package/dist/index.js CHANGED
@@ -104,6 +104,20 @@ function assertOAuthConfig(auth2) {
104
104
  for (const algorithm of auth2.algorithms)
105
105
  assertJwtAlgorithm(algorithm);
106
106
  }
107
+ if (auth2.accessTokenTyp !== void 0) {
108
+ if (!Array.isArray(auth2.accessTokenTyp)) {
109
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
110
+ }
111
+ if (auth2.accessTokenTyp.length === 0) {
112
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
113
+ }
114
+ for (const typ of auth2.accessTokenTyp) {
115
+ if (typeof typ !== "string") {
116
+ throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
117
+ }
118
+ assertNonEmptyString("auth.accessTokenTyp", typ);
119
+ }
120
+ }
107
121
  if (auth2.clockToleranceSeconds !== void 0)
108
122
  assertClockToleranceSeconds(auth2.clockToleranceSeconds);
109
123
  if (auth2.resource === void 0 && auth2.acceptedAudiences === void 0) {
@@ -119,6 +133,8 @@ function freezeAuth(auth2) {
119
133
  Object.freeze(auth2.requiredScopes);
120
134
  if (auth2.algorithms)
121
135
  Object.freeze(auth2.algorithms);
136
+ if (auth2.accessTokenTyp)
137
+ Object.freeze(auth2.accessTokenTyp);
122
138
  Object.freeze(auth2);
123
139
  }
124
140
  function defineTool(def) {
@@ -159,7 +175,8 @@ function issuer(options) {
159
175
  ...options,
160
176
  acceptedAudiences: frozenAudiences(options.acceptedAudiences),
161
177
  requiredScopes: frozenArray(options.requiredScopes),
162
- algorithms: frozenArray(options.algorithms)
178
+ algorithms: frozenArray(options.algorithms),
179
+ accessTokenTyp: frozenArray(options.accessTokenTyp)
163
180
  })
164
181
  );
165
182
  }
@@ -281,6 +281,7 @@ function stringClaim(claims, name) {
281
281
  // src/auth/verifier.ts
282
282
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
283
283
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
284
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
284
285
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
285
286
  var OAuthTokenError = class extends Error {
286
287
  constructor(status, oauthError, message) {
@@ -313,10 +314,23 @@ async function fetchVerificationKeySet(jwksUri) {
313
314
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
314
315
  }
315
316
  }
317
+ function assertAccessTokenTyp(token, allowed) {
318
+ let header;
319
+ try {
320
+ header = (0, import_jose.decodeProtectedHeader)(token);
321
+ } catch (err) {
322
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
323
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
324
+ }
325
+ const typ = header.typ;
326
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
327
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
328
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
329
+ }
330
+ }
316
331
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
317
332
  try {
318
333
  const { payload } = await (0, import_jose.jwtVerify)(token, keySet, {
319
- typ: "at+jwt",
320
334
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
321
335
  // `iss` carries the slash the AS publishes still verifies.
322
336
  issuer: [issuer, `${issuer}/`],
@@ -365,6 +379,7 @@ function buildMcpAuthContext(args) {
365
379
  };
366
380
  }
367
381
  function createOAuthTokenVerifier(auth, discovery) {
382
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
368
383
  return async (token, request, options) => {
369
384
  const resource = resolveProtectedResource(auth, request, options);
370
385
  const issuer = await discovery.resolveIssuer();
@@ -373,6 +388,7 @@ function createOAuthTokenVerifier(auth, discovery) {
373
388
  const jwksUri = await discovery.resolveJwksUri();
374
389
  log.debug("oauth.jwks.fetch", { jwksUri });
375
390
  const keySet = await fetchVerificationKeySet(jwksUri);
391
+ assertAccessTokenTyp(token, allowedTyps);
376
392
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
377
393
  assertNonEmptySubject(claims);
378
394
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type McpProtocolHandler = (request: Request) => Promise<Response>;
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type McpProtocolHandler = (request: Request) => Promise<Response>;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-DF3DD3KD.js";
3
+ } from "../../chunk-WLNT2FX7.js";
4
4
  import "../../chunk-MA5H6PSF.js";
5
- import "../../chunk-LAFJDJRY.js";
5
+ import "../../chunk-G4XA7IJM.js";
6
6
  import "../../chunk-QC3DXQTH.js";
7
7
  import "../../chunk-6DXGZZA4.js";
8
8
  export {
@@ -283,6 +283,7 @@ function stringClaim(claims, name) {
283
283
  // src/auth/verifier.ts
284
284
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
285
285
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
286
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
286
287
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
287
288
  var OAuthTokenError = class extends Error {
288
289
  constructor(status, oauthError, message) {
@@ -315,10 +316,23 @@ async function fetchVerificationKeySet(jwksUri) {
315
316
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
316
317
  }
317
318
  }
319
+ function assertAccessTokenTyp(token, allowed) {
320
+ let header;
321
+ try {
322
+ header = (0, import_jose.decodeProtectedHeader)(token);
323
+ } catch (err) {
324
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
325
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
326
+ }
327
+ const typ = header.typ;
328
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
329
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
330
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
331
+ }
332
+ }
318
333
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
319
334
  try {
320
335
  const { payload } = await (0, import_jose.jwtVerify)(token, keySet, {
321
- typ: "at+jwt",
322
336
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
323
337
  // `iss` carries the slash the AS publishes still verifies.
324
338
  issuer: [issuer, `${issuer}/`],
@@ -367,6 +381,7 @@ function buildMcpAuthContext(args) {
367
381
  };
368
382
  }
369
383
  function createOAuthTokenVerifier(auth, discovery) {
384
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
370
385
  return async (token, request, options) => {
371
386
  const resource = resolveProtectedResource(auth, request, options);
372
387
  const issuer = await discovery.resolveIssuer();
@@ -375,6 +390,7 @@ function createOAuthTokenVerifier(auth, discovery) {
375
390
  const jwksUri = await discovery.resolveJwksUri();
376
391
  log.debug("oauth.jwks.fetch", { jwksUri });
377
392
  const keySet = await fetchVerificationKeySet(jwksUri);
393
+ assertAccessTokenTyp(token, allowedTyps);
378
394
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
379
395
  assertNonEmptySubject(claims);
380
396
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type OAuthProtectedResourceMetadataHandler = (request: Request) => Promise<Response>;
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type OAuthProtectedResourceMetadataHandler = (request: Request) => Promise<Response>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createOAuthProtectedResourceMetadataHandler
3
- } from "../chunk-X7V2CL7C.js";
4
- import "../chunk-LAFJDJRY.js";
3
+ } from "../chunk-QDKOF4UF.js";
4
+ import "../chunk-G4XA7IJM.js";
5
5
  import "../chunk-QC3DXQTH.js";
6
6
  import "../chunk-6DXGZZA4.js";
7
7
  export {
@@ -291,6 +291,7 @@ function stringClaim(claims, name) {
291
291
  // src/auth/verifier.ts
292
292
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
293
293
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
294
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
294
295
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
295
296
  var OAuthTokenError = class extends Error {
296
297
  constructor(status, oauthError, message) {
@@ -323,10 +324,23 @@ async function fetchVerificationKeySet(jwksUri) {
323
324
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
324
325
  }
325
326
  }
327
+ function assertAccessTokenTyp(token, allowed) {
328
+ let header;
329
+ try {
330
+ header = (0, import_jose.decodeProtectedHeader)(token);
331
+ } catch (err) {
332
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
333
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
334
+ }
335
+ const typ = header.typ;
336
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
337
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
338
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
339
+ }
340
+ }
326
341
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
327
342
  try {
328
343
  const { payload } = await (0, import_jose.jwtVerify)(token, keySet, {
329
- typ: "at+jwt",
330
344
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
331
345
  // `iss` carries the slash the AS publishes still verifies.
332
346
  issuer: [issuer, `${issuer}/`],
@@ -375,6 +389,7 @@ function buildMcpAuthContext(args) {
375
389
  };
376
390
  }
377
391
  function createOAuthTokenVerifier(auth, discovery) {
392
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
378
393
  return async (token, request, options) => {
379
394
  const resource = resolveProtectedResource(auth, request, options);
380
395
  const issuer = await discovery.resolveIssuer();
@@ -383,6 +398,7 @@ function createOAuthTokenVerifier(auth, discovery) {
383
398
  const jwksUri = await discovery.resolveJwksUri();
384
399
  log.debug("oauth.jwks.fetch", { jwksUri });
385
400
  const keySet = await fetchVerificationKeySet(jwksUri);
401
+ assertAccessTokenTyp(token, allowedTyps);
386
402
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
387
403
  assertNonEmptySubject(claims);
388
404
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type RestListToolsHandler = (request: Request) => Promise<Response>;
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  type RestListToolsHandler = (request: Request) => Promise<Response>;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-SZLSAGDF.js";
3
+ } from "../../chunk-YWLMMDET.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-PJXKJNSZ.js";
6
+ } from "../../chunk-VNRQPA4K.js";
7
7
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-LAFJDJRY.js";
8
+ import "../../chunk-G4XA7IJM.js";
9
9
  import "../../chunk-QC3DXQTH.js";
10
10
  import "../../chunk-6DXGZZA4.js";
11
11
  export {
@@ -290,6 +290,7 @@ function stringClaim(claims, name) {
290
290
  // src/auth/verifier.ts
291
291
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
292
292
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
293
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
293
294
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
294
295
  var OAuthTokenError = class extends Error {
295
296
  constructor(status, oauthError, message) {
@@ -322,10 +323,23 @@ async function fetchVerificationKeySet(jwksUri) {
322
323
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
323
324
  }
324
325
  }
326
+ function assertAccessTokenTyp(token, allowed) {
327
+ let header;
328
+ try {
329
+ header = (0, import_jose.decodeProtectedHeader)(token);
330
+ } catch (err) {
331
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
332
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
333
+ }
334
+ const typ = header.typ;
335
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
336
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
337
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
338
+ }
339
+ }
325
340
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
326
341
  try {
327
342
  const { payload } = await (0, import_jose.jwtVerify)(token, keySet, {
328
- typ: "at+jwt",
329
343
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
330
344
  // `iss` carries the slash the AS publishes still verifies.
331
345
  issuer: [issuer, `${issuer}/`],
@@ -374,6 +388,7 @@ function buildMcpAuthContext(args) {
374
388
  };
375
389
  }
376
390
  function createOAuthTokenVerifier(auth, discovery) {
391
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
377
392
  return async (token, request, options) => {
378
393
  const resource = resolveProtectedResource(auth, request, options);
379
394
  const issuer = await discovery.resolveIssuer();
@@ -382,6 +397,7 @@ function createOAuthTokenVerifier(auth, discovery) {
382
397
  const jwksUri = await discovery.resolveJwksUri();
383
398
  log.debug("oauth.jwks.fetch", { jwksUri });
384
399
  const keySet = await fetchVerificationKeySet(jwksUri);
400
+ assertAccessTokenTyp(token, allowedTyps);
385
401
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
386
402
  assertNonEmptySubject(claims);
387
403
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -908,6 +924,16 @@ function dispatchFor(pathname) {
908
924
  }
909
925
  return { kind: "mcp" };
910
926
  }
927
+ function applyForwardedProto(request) {
928
+ const proto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
929
+ if (!proto)
930
+ return request;
931
+ const url = new URL(request.url);
932
+ if (`${proto}:` === url.protocol)
933
+ return request;
934
+ url.protocol = `${proto}:`;
935
+ return new Request(url.href, request);
936
+ }
911
937
  function createSupabaseHandler(mcp, options = {}) {
912
938
  const resourcePath = deriveResourcePath(options);
913
939
  if (resourcePath !== void 0)
@@ -920,16 +946,17 @@ function createSupabaseHandler(mcp, options = {}) {
920
946
  const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
921
947
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
922
948
  return async (request) => {
923
- const target = dispatchFor(new URL(request.url).pathname);
949
+ const req = applyForwardedProto(request);
950
+ const target = dispatchFor(new URL(req.url).pathname);
924
951
  switch (target.kind) {
925
952
  case "metadata":
926
- return metadataHandler(request);
953
+ return metadataHandler(req);
927
954
  case "list-tools":
928
- return listToolsHandler(request);
955
+ return listToolsHandler(req);
929
956
  case "invoke-tool":
930
- return invokeToolHandler(request, target.toolName);
957
+ return invokeToolHandler(req, target.toolName);
931
958
  case "mcp":
932
- return mcpHandler(request);
959
+ return mcpHandler(req);
933
960
  }
934
961
  };
935
962
  }
@@ -1,4 +1,4 @@
1
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
1
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
2
2
  import 'zod';
3
3
 
4
4
  type SupabaseHandler = (request: Request) => Promise<Response>;
@@ -1,4 +1,4 @@
1
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
1
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
2
2
  import 'zod';
3
3
 
4
4
  type SupabaseHandler = (request: Request) => Promise<Response>;
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-DF3DD3KD.js";
3
+ } from "../../chunk-WLNT2FX7.js";
4
4
  import {
5
5
  createOAuthProtectedResourceMetadataHandler
6
- } from "../../chunk-X7V2CL7C.js";
6
+ } from "../../chunk-QDKOF4UF.js";
7
7
  import {
8
8
  createInvokeToolHandler
9
- } from "../../chunk-SZLSAGDF.js";
9
+ } from "../../chunk-YWLMMDET.js";
10
10
  import {
11
11
  createListToolsHandler
12
- } from "../../chunk-PJXKJNSZ.js";
12
+ } from "../../chunk-VNRQPA4K.js";
13
13
  import "../../chunk-MA5H6PSF.js";
14
14
  import {
15
15
  assertResourcePathShape
16
- } from "../../chunk-LAFJDJRY.js";
16
+ } from "../../chunk-G4XA7IJM.js";
17
17
  import {
18
18
  trimTrailingSlash
19
19
  } from "../../chunk-QC3DXQTH.js";
@@ -54,6 +54,16 @@ function dispatchFor(pathname) {
54
54
  }
55
55
  return { kind: "mcp" };
56
56
  }
57
+ function applyForwardedProto(request) {
58
+ const proto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
59
+ if (!proto)
60
+ return request;
61
+ const url = new URL(request.url);
62
+ if (`${proto}:` === url.protocol)
63
+ return request;
64
+ url.protocol = `${proto}:`;
65
+ return new Request(url.href, request);
66
+ }
57
67
  function createSupabaseHandler(mcp, options = {}) {
58
68
  const resourcePath = deriveResourcePath(options);
59
69
  if (resourcePath !== void 0)
@@ -66,16 +76,17 @@ function createSupabaseHandler(mcp, options = {}) {
66
76
  const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
67
77
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
68
78
  return async (request) => {
69
- const target = dispatchFor(new URL(request.url).pathname);
79
+ const req = applyForwardedProto(request);
80
+ const target = dispatchFor(new URL(req.url).pathname);
70
81
  switch (target.kind) {
71
82
  case "metadata":
72
- return metadataHandler(request);
83
+ return metadataHandler(req);
73
84
  case "list-tools":
74
- return listToolsHandler(request);
85
+ return listToolsHandler(req);
75
86
  case "invoke-tool":
76
- return invokeToolHandler(request, target.toolName);
87
+ return invokeToolHandler(req, target.toolName);
77
88
  case "mcp":
78
- return mcpHandler(request);
89
+ return mcpHandler(req);
79
90
  }
80
91
  };
81
92
  }
@@ -31,7 +31,7 @@ var import_node_fs = require("fs");
31
31
  var import_node_path = require("path");
32
32
 
33
33
  // package.json
34
- var version = "0.10.0";
34
+ var version = "0.11.0";
35
35
 
36
36
  // src/core/fs-errors.ts
37
37
  function isFileMissing(err) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  version
3
- } from "../../chunk-4XJ2R3DD.js";
3
+ } from "../../chunk-ENWRS6AT.js";
4
4
  import {
5
5
  isFileMissing
6
6
  } from "../../chunk-Y3ZFPEQH.js";
@@ -293,6 +293,7 @@ function stringClaim(claims, name) {
293
293
  // src/auth/verifier.ts
294
294
  var DEFAULT_JWT_ALGORITHMS = ["RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"];
295
295
  var DEFAULT_CLOCK_TOLERANCE_SECONDS = 30;
296
+ var DEFAULT_ACCESS_TOKEN_TYPS = ["at+jwt", "JWT"];
296
297
  var JWKS_FETCH_TIMEOUT_MS = 5e3;
297
298
  var OAuthTokenError = class extends Error {
298
299
  constructor(status, oauthError, message) {
@@ -325,10 +326,23 @@ async function fetchVerificationKeySet(jwksUri) {
325
326
  throw new OAuthConfigurationError(`JWKS fetch failed: ${err instanceof Error ? err.message : String(err)}`);
326
327
  }
327
328
  }
329
+ function assertAccessTokenTyp(token, allowed) {
330
+ let header;
331
+ try {
332
+ header = (0, import_jose.decodeProtectedHeader)(token);
333
+ } catch (err) {
334
+ log.debug("oauth.verify.bad_header", { ...describeError(err), outcome: "401 invalid_token" });
335
+ throw new OAuthTokenError(401, "invalid_token", "Malformed JWT header");
336
+ }
337
+ const typ = header.typ;
338
+ if (typeof typ !== "string" || !allowed.includes(typ)) {
339
+ log.debug("oauth.verify.bad_typ", { jwtTyp: typ, allowed, outcome: "401 invalid_token" });
340
+ throw new OAuthTokenError(401, "invalid_token", "Access token typ header is not accepted");
341
+ }
342
+ }
328
343
  async function verifyJwtClaims(token, keySet, issuer, audience, auth) {
329
344
  try {
330
345
  const { payload } = await (0, import_jose.jwtVerify)(token, keySet, {
331
- typ: "at+jwt",
332
346
  // `issuer` is trimmed of any trailing slash; accept both forms so a token whose
333
347
  // `iss` carries the slash the AS publishes still verifies.
334
348
  issuer: [issuer, `${issuer}/`],
@@ -377,6 +391,7 @@ function buildMcpAuthContext(args) {
377
391
  };
378
392
  }
379
393
  function createOAuthTokenVerifier(auth, discovery) {
394
+ const allowedTyps = auth.accessTokenTyp ?? DEFAULT_ACCESS_TOKEN_TYPS;
380
395
  return async (token, request, options) => {
381
396
  const resource = resolveProtectedResource(auth, request, options);
382
397
  const issuer = await discovery.resolveIssuer();
@@ -385,6 +400,7 @@ function createOAuthTokenVerifier(auth, discovery) {
385
400
  const jwksUri = await discovery.resolveJwksUri();
386
401
  log.debug("oauth.jwks.fetch", { jwksUri });
387
402
  const keySet = await fetchVerificationKeySet(jwksUri);
403
+ assertAccessTokenTyp(token, allowedTyps);
388
404
  const claims = await verifyJwtClaims(token, keySet, issuer, acceptedAudiences, auth);
389
405
  assertNonEmptySubject(claims);
390
406
  const context = buildMcpAuthContext({ token, claims, issuer, resource, acceptedAudiences });
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  interface TanStackRouteCtx {
@@ -1,5 +1,5 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-HTd0GKmB.js';
2
- import { d as McpDefinition } from '../../types-C5SSORxe.js';
2
+ import { d as McpDefinition } from '../../types-BanzncFh.js';
3
3
  import 'zod';
4
4
 
5
5
  interface TanStackRouteCtx {
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-DF3DD3KD.js";
3
+ } from "../../chunk-WLNT2FX7.js";
4
4
  import {
5
5
  createOAuthProtectedResourceMetadataHandler
6
- } from "../../chunk-X7V2CL7C.js";
6
+ } from "../../chunk-QDKOF4UF.js";
7
7
  import {
8
8
  createInvokeToolHandler
9
- } from "../../chunk-SZLSAGDF.js";
9
+ } from "../../chunk-YWLMMDET.js";
10
10
  import {
11
11
  createListToolsHandler
12
- } from "../../chunk-PJXKJNSZ.js";
12
+ } from "../../chunk-VNRQPA4K.js";
13
13
  import "../../chunk-MA5H6PSF.js";
14
- import "../../chunk-LAFJDJRY.js";
14
+ import "../../chunk-G4XA7IJM.js";
15
15
  import "../../chunk-QC3DXQTH.js";
16
16
  import "../../chunk-6DXGZZA4.js";
17
17
 
@@ -64,6 +64,14 @@ interface McpAuthConfig {
64
64
  readonly jwksUri?: string;
65
65
  readonly algorithms?: readonly string[];
66
66
  readonly clockToleranceSeconds?: number;
67
+ /**
68
+ * Allowed values for the access token's JOSE `typ` header. Defaults to
69
+ * `["at+jwt", "JWT"]` so both the RFC 9068 access-token shape and the plain
70
+ * user-JWT shape (notably Supabase GoTrue's OAuth tokens) are accepted out of
71
+ * the box. Pin to `["at+jwt"]` to enforce strict RFC 9068. The header `typ`
72
+ * must be present and string-typed; this option only controls which values pass.
73
+ */
74
+ readonly accessTokenTyp?: readonly string[];
67
75
  }
68
76
 
69
77
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/mcp-js",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
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": {