@lovable.dev/mcp-js 0.28.0 → 0.29.0-rc.1

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 (69) hide show
  1. package/README.md +7 -1
  2. package/dist/{authorize-Cs1yyLrq.d.ts → authorize-BjNE3LPr.d.ts} +1 -1
  3. package/dist/{authorize-BcNuNPtP.d.cts → authorize-BzZFS0zi.d.cts} +1 -1
  4. package/dist/{base-CUkmyaXJ.d.cts → base-C8osWdMU.d.cts} +3 -0
  5. package/dist/{base-CUkmyaXJ.d.ts → base-C8osWdMU.d.ts} +3 -0
  6. package/dist/cli/extract-manifest.cjs +2 -2
  7. package/dist/cli/extract-manifest.js +2 -2
  8. package/dist/{authorize--rUeMOGU.js → cors-BDTQQJE2.js} +68 -24
  9. package/dist/{authorize-ChY44o_1.cjs → cors-BRv5KXKQ.cjs} +73 -29
  10. package/dist/{forwarded-BlLF3dfc.js → forwarded-B3EBjHnA.js} +3 -3
  11. package/dist/{forwarded-Bhwcj22u.cjs → forwarded-BC_RHnn5.cjs} +3 -3
  12. package/dist/{gate-CGZl0gjJ.cjs → gate-CAJSRt_t.cjs} +6 -4
  13. package/dist/{gate-BiM6EBeA.js → gate-uCVrbDBb.js} +5 -3
  14. package/dist/index.cjs +37 -0
  15. package/dist/index.d.cts +3 -3
  16. package/dist/index.d.ts +3 -3
  17. package/dist/index.js +37 -0
  18. package/dist/{io-SMlD5WeX.d.ts → io-BYUyNFdn.d.ts} +1 -1
  19. package/dist/{io-VBHO8YH_.d.cts → io-B_YLNWDL.d.cts} +1 -1
  20. package/dist/{list-tools-BLGr7mot.js → list-tools-C1OiTDR9.js} +9 -13
  21. package/dist/{list-tools-BN97L2Yv.d.cts → list-tools-C3AoI2Zw.d.cts} +3 -3
  22. package/dist/list-tools-DES10avA.cjs +48 -0
  23. package/dist/{list-tools-BAqQVIHk.d.ts → list-tools-DXqSPvNY.d.ts} +3 -3
  24. package/dist/mcp-C9B7o75m.cjs +345 -0
  25. package/dist/mcp-HDkUr85V.js +340 -0
  26. package/dist/{package-DgiA0xuY.js → package-BI5r4uGM.js} +1 -1
  27. package/dist/{package-CGLPZwz-.cjs → package-ClCIqol1.cjs} +1 -1
  28. package/dist/protocols/mcp/index.cjs +1 -1
  29. package/dist/protocols/mcp/index.d.cts +3 -3
  30. package/dist/protocols/mcp/index.d.ts +3 -3
  31. package/dist/protocols/mcp/index.js +1 -1
  32. package/dist/protocols/oauth-metadata.cjs +11 -9
  33. package/dist/protocols/oauth-metadata.d.cts +2 -2
  34. package/dist/protocols/oauth-metadata.d.ts +2 -2
  35. package/dist/protocols/oauth-metadata.js +5 -3
  36. package/dist/protocols/rest/index.cjs +2 -2
  37. package/dist/protocols/rest/index.d.cts +4 -4
  38. package/dist/protocols/rest/index.d.ts +4 -4
  39. package/dist/protocols/rest/index.js +2 -2
  40. package/dist/{rest-BE05MUNS.cjs → rest-BBdfHMGh.cjs} +28 -27
  41. package/dist/{rest-BS7bBOd9.js → rest-Cr7NhxL3.js} +13 -12
  42. package/dist/schema-CW1jKvio.js +65 -0
  43. package/dist/schema-D3vClxb7.cjs +76 -0
  44. package/dist/stacks/supabase/index.cjs +7 -7
  45. package/dist/stacks/supabase/index.d.cts +1 -1
  46. package/dist/stacks/supabase/index.d.ts +1 -1
  47. package/dist/stacks/supabase/index.js +5 -5
  48. package/dist/stacks/supabase/vite.cjs +1 -1
  49. package/dist/stacks/supabase/vite.d.cts +1 -1
  50. package/dist/stacks/supabase/vite.d.ts +1 -1
  51. package/dist/stacks/supabase/vite.js +1 -1
  52. package/dist/stacks/tanstack/index.cjs +8 -8
  53. package/dist/stacks/tanstack/index.d.cts +2 -2
  54. package/dist/stacks/tanstack/index.d.ts +2 -2
  55. package/dist/stacks/tanstack/index.js +5 -5
  56. package/dist/stacks/tanstack/vite.cjs +8 -4
  57. package/dist/stacks/tanstack/vite.d.cts +7 -1
  58. package/dist/stacks/tanstack/vite.d.ts +7 -1
  59. package/dist/stacks/tanstack/vite.js +8 -4
  60. package/dist/tool-result-CK6hXO43.cjs +89 -0
  61. package/dist/tool-result-DfCk445b.js +78 -0
  62. package/dist/{types-C0Wgm9zp.d.cts → types-D1cgsnPu.d.cts} +15 -7
  63. package/dist/{types-C0Wgm9zp.d.ts → types-D1cgsnPu.d.ts} +15 -7
  64. package/package.json +2 -1
  65. package/dist/content-D5LJAHyM.js +0 -12
  66. package/dist/content-NCYIGgOb.cjs +0 -17
  67. package/dist/list-tools-DCF6G4fn.cjs +0 -52
  68. package/dist/mcp-CUGwXkxb.cjs +0 -153
  69. package/dist/mcp-Czp-hHjN.js +0 -148
package/README.md CHANGED
@@ -51,7 +51,13 @@ That's the whole authoring surface. No imperative server construction, no route
51
51
 
52
52
  The table shows the default `path: "/mcp"`. The REST companions co-locate under the parent of the configured `path`, so `mcpPlugin({ path: "/api/public/mcp" })` emits them at `/api/public/.mcp/list-tools` and `/api/public/.mcp/invoke-tool/<tool>` (file: `src/routes/api/public/[.mcp]/...`). Pass `restRoutes: false` to drop them.
53
53
 
54
- MCP (`POST <path>`, `/mcp` by default) is the public wire format clients speak directly. REST (the `.mcp/*` companions, co-located under the `path` parent) is internal RPC — only an upstream MCP proxy calls it; never a browser or a hand-rolled client. All runtime routes import the same `defineMcp` result, so they stay in sync on which tools exist and which auth policy protects them. If `defineMcp({ auth: ... })` is omitted, the handlers stay unauthenticated; if OAuth auth is configured, MCP and REST both require the proxy/client to pass `Authorization: Bearer <token>`. CORS and rate limiting still belong at the app host or edge.
54
+ MCP (`POST <path>`, `/mcp` by default) is the public wire format clients speak directly. REST (the `.mcp/*` companions, co-located under the `path` parent) is internal RPC — only an upstream MCP proxy calls it; never a browser or a hand-rolled client. All runtime routes import the same `defineMcp` result, so they stay in sync on which tools exist and which auth and browser-origin policies protect them. If `defineMcp({ auth: ... })` is omitted, the handlers stay unauthenticated; if OAuth auth is configured, MCP and REST both require the proxy/client to pass `Authorization: Bearer <token>`. Rate limiting belongs at the app host or edge.
55
+
56
+ The MCP endpoint supports both protocol eras on one URL. Finalized `2026-07-28` clients send the version, client capabilities, and mirrored HTTP headers on every request; the server returns typed results plus cache metadata on discovery and list responses without initialization or protocol sessions. Initialization-era clients continue through a stateless compatibility path: `initialize`, `tools/list`, and `tools/call` work as independent requests, and the endpoint never mints `Mcp-Session-Id`. `GET` and `DELETE` return `405` because there is no standalone stream or session to manage.
57
+
58
+ `outputSchema` accepts either the existing object-shape shorthand (`{ value: z.string() }`) or a JSON-Schema-representable Zod schema such as `z.array(z.string())`; `structuredContent` may be any JSON value. The server returns the schema's parsed output, so coercions are reflected in the result; transforms with no truthful JSON Schema are rejected when `defineMcp` runs. Modern clients receive the natural schema and value. The compatibility path wraps non-object schemas and values under `result` for initialization-era clients whose wire format requires an object root.
59
+
60
+ Browser-origin checks apply to the MCP, REST companion, and OAuth metadata routes before authentication. Omit `allowedOrigins` to allow requests with no `Origin` header (Go, desktop, CLI, and server clients) plus same-origin browser requests. Set `allowedOrigins: ["https://client.example.com"]` for exact additional origins, or `allowedOrigins: "any"` to intentionally restore wildcard CORS. Exact and same origins are reflected with `Vary: Origin`; other browser origins receive `403` without an OAuth challenge. Reverse-proxy adapters compare against the effective public origin after applying only their configured trusted forwarded headers.
55
61
 
56
62
  The OAuth metadata route is emitted by default and returns `404` until OAuth auth is configured. Disable it with `mcpPlugin({ protectedResourceMetadataRoute: false })` only if the app owns `/.well-known/oauth-protected-resource` itself.
57
63
 
@@ -1,4 +1,4 @@
1
- import "./types-C0Wgm9zp.js";
1
+ import "./types-D1cgsnPu.js";
2
2
  //#region src/auth/authorize.d.ts
3
3
  interface McpRuntimeOptions {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "./types-C0Wgm9zp.cjs";
1
+ import "./types-D1cgsnPu.cjs";
2
2
  //#region src/auth/authorize.d.ts
3
3
  interface McpRuntimeOptions {
4
4
  /**
@@ -16,6 +16,9 @@ interface InvocationRecord {
16
16
  /** HTTP request method. Set on `auth_challenge` so probe traffic (GET vs
17
17
  * POST discovery) is distinguishable; absent on tool-call records. */
18
18
  httpMethod?: string;
19
+ /** Wire surface that served the call; absent on records emitted before
20
+ * protocol classification (auth gate, transport faults). */
21
+ protocol?: "2026-07-28" | "legacy" | "rest";
19
22
  /** The app end-user that made the call (the access token `sub`), or
20
23
  * `undefined` when the request is unauthenticated. Not a Lovable identity. */
21
24
  endUserId?: string;
@@ -16,6 +16,9 @@ interface InvocationRecord {
16
16
  /** HTTP request method. Set on `auth_challenge` so probe traffic (GET vs
17
17
  * POST discovery) is distinguishable; absent on tool-call records. */
18
18
  httpMethod?: string;
19
+ /** Wire surface that served the call; absent on records emitted before
20
+ * protocol classification (auth gate, transport faults). */
21
+ protocol?: "2026-07-28" | "legacy" | "rest";
19
22
  /** The app end-user that made the call (the access token `sub`), or
20
23
  * `undefined` when the request is unauthenticated. Not a Lovable identity. */
21
24
  endUserId?: string;
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- const require_package = require("../package-CGLPZwz-.cjs");
3
- const require_list_tools = require("../list-tools-DCF6G4fn.cjs");
2
+ const require_package = require("../package-ClCIqol1.cjs");
3
+ const require_list_tools = require("../list-tools-DES10avA.cjs");
4
4
  const require_fs_errors = require("../fs-errors-CWNzOV75.cjs");
5
5
  let node_fs = require("node:fs");
6
6
  let node_path = require("node:path");
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { t as version } from "../package-DgiA0xuY.js";
3
- import { t as buildMcpListing } from "../list-tools-BLGr7mot.js";
2
+ import { t as version } from "../package-BI5r4uGM.js";
3
+ import { t as buildMcpListing } from "../list-tools-C1OiTDR9.js";
4
4
  import { t as isFileMissing } from "../fs-errors-PA2t1TIp.js";
5
5
  import { lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
6
6
  import { dirname, resolve } from "node:path";
@@ -1,28 +1,7 @@
1
1
  import { i as log, n as applyLogLevelFromEnv, o as parseSafeUrl, r as describeError, s as trimTrailingSlash, t as LOG_LEVEL_ENV_VAR, u as resolveMetricsConfig } from "./logger-Ctv5xUSD.js";
2
- import { t as version } from "./package-DgiA0xuY.js";
2
+ import { t as version } from "./package-BI5r4uGM.js";
3
3
  import "./metadata-path-CAkNcfyY.js";
4
4
  import { createLocalJWKSet, decodeProtectedHeader, errors, jwtVerify } from "jose";
5
- //#region src/core/cors.ts
6
- const EXPOSE_HEADERS = "WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version";
7
- const ALLOW_HEADERS = "Authorization, Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID";
8
- /** Add permissive CORS to a built response, preserving its other headers. */
9
- function withCors(response) {
10
- response.headers.set("Access-Control-Allow-Origin", "*");
11
- response.headers.set("Access-Control-Expose-Headers", EXPOSE_HEADERS);
12
- return response;
13
- }
14
- function corsPreflightResponse(allowMethods) {
15
- return new Response(null, {
16
- status: 204,
17
- headers: {
18
- "Access-Control-Allow-Origin": "*",
19
- "Access-Control-Allow-Methods": allowMethods,
20
- "Access-Control-Allow-Headers": ALLOW_HEADERS,
21
- "Access-Control-Max-Age": "86400"
22
- }
23
- });
24
- }
25
- //#endregion
26
5
  //#region src/core/http.ts
27
6
  const JSON_HEADERS = { "Content-Type": "application/json" };
28
7
  /** Strip the body from a built response, preserving status and headers, for HEAD. */
@@ -34,7 +13,7 @@ function headResponse(response) {
34
13
  });
35
14
  }
36
15
  function finalizeWireResponse(request, response) {
37
- return withCors(request.method === "HEAD" ? headResponse(response) : response);
16
+ return request.method === "HEAD" ? headResponse(response) : response;
38
17
  }
39
18
  function methodNotAllowed(allow) {
40
19
  return new Response(JSON.stringify({ error: "method not allowed" }), {
@@ -74,6 +53,7 @@ function toLogRecord(rec) {
74
53
  if (rec.reqBytes !== void 0) attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
75
54
  if (rec.resBytes !== void 0) attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
76
55
  if (rec.httpMethod !== void 0) attributes.push(strAttr("http.request.method", rec.httpMethod));
56
+ if (rec.protocol !== void 0) attributes.push(strAttr("mcp.protocol", rec.protocol));
77
57
  attributes.push(strAttr("mcp.stack", rec.stack));
78
58
  if (rec.endUserId !== void 0) attributes.push(strAttr("mcp.end_user_id", rec.endUserId));
79
59
  return {
@@ -177,6 +157,7 @@ var BaseMetricRecorder = class {
177
157
  outcome: ev.outcome,
178
158
  durationMs: ev.durationMs,
179
159
  stack: this.stack,
160
+ ...ev.protocol !== void 0 && { protocol: ev.protocol },
180
161
  ...ev.errorText !== void 0 && { errorText: ev.errorText }
181
162
  });
182
163
  if (!this.config.enabled) return;
@@ -959,4 +940,67 @@ function createRequestAuthorizer(mcp, options = {}) {
959
940
  } };
960
941
  }
961
942
  //#endregion
962
- export { assertResourcePathShape as a, createNoopRecorder as c, finalizeWireResponse as d, methodNotAllowed as f, oauthConfigurationErrorResponse as i, nowMs as l, createRequestAuthorizer as n, resolveProtectedResource as o, corsPreflightResponse as p, getOAuthRuntime as r, createRecorderForRuntime as s, assertRestResourceBinding as t, JSON_HEADERS as u };
943
+ //#region src/core/cors.ts
944
+ const EXPOSE_HEADERS = "WWW-Authenticate, MCP-Protocol-Version, Mcp-Session-Id";
945
+ const ALLOW_HEADERS = "Authorization, Content-Type, MCP-Protocol-Version, Mcp-Method, Mcp-Name, Mcp-Session-Id, Last-Event-ID";
946
+ const MCP_PARAM_HEADER = /^mcp-param-[!#$%&'*+.^_`|~0-9A-Za-z-]+$/i;
947
+ function appendVary(headers, value) {
948
+ const values = new Set((headers.get("Vary") ?? "").split(",").map((entry) => entry.trim()).filter(Boolean));
949
+ values.add(value);
950
+ headers.set("Vary", [...values].join(", "));
951
+ }
952
+ function addCorsHeaders(response, allowedOrigin, variesByOrigin) {
953
+ if (allowedOrigin !== void 0) {
954
+ response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
955
+ response.headers.set("Access-Control-Expose-Headers", EXPOSE_HEADERS);
956
+ }
957
+ if (variesByOrigin) appendVary(response.headers, "Origin");
958
+ return response;
959
+ }
960
+ function allowedRequestHeaders(request) {
961
+ const allowed = new Map(ALLOW_HEADERS.split(", ").map((header) => [header.toLowerCase(), header]));
962
+ for (const header of (request.headers.get("Access-Control-Request-Headers") ?? "").split(",")) {
963
+ const normalized = header.trim();
964
+ if (MCP_PARAM_HEADER.test(normalized)) allowed.set(normalized.toLowerCase(), normalized);
965
+ }
966
+ return [...allowed.values()].join(", ");
967
+ }
968
+ function evaluateCors(request, allowedOrigins) {
969
+ const origin = request.headers.get("Origin");
970
+ const allowAny = allowedOrigins === "any";
971
+ let allowedOrigin;
972
+ if (allowAny) allowedOrigin = "*";
973
+ else if (origin === null) allowedOrigin = void 0;
974
+ else if (origin === new URL(request.url).origin || allowedOrigins?.includes(origin)) allowedOrigin = origin;
975
+ else allowedOrigin = null;
976
+ if (allowedOrigin === null) {
977
+ const response = Response.json({ error: "origin not allowed" }, {
978
+ status: 403,
979
+ headers: { "Cache-Control": "no-store" }
980
+ });
981
+ appendVary(response.headers, "Origin");
982
+ return {
983
+ ok: false,
984
+ response
985
+ };
986
+ }
987
+ return {
988
+ ok: true,
989
+ withHeaders: (response) => addCorsHeaders(response, allowedOrigin, !allowAny),
990
+ preflight: (allowMethods) => {
991
+ const requestedHeaders = request.headers.get("Access-Control-Request-Headers");
992
+ const response = new Response(null, {
993
+ status: 204,
994
+ headers: {
995
+ "Access-Control-Allow-Methods": allowMethods,
996
+ "Access-Control-Allow-Headers": allowedRequestHeaders(request),
997
+ "Access-Control-Max-Age": "86400"
998
+ }
999
+ });
1000
+ if (requestedHeaders) appendVary(response.headers, "Access-Control-Request-Headers");
1001
+ return addCorsHeaders(response, allowedOrigin, !allowAny);
1002
+ }
1003
+ };
1004
+ }
1005
+ //#endregion
1006
+ export { oauthConfigurationErrorResponse as a, createRecorderForRuntime as c, JSON_HEADERS as d, finalizeWireResponse as f, getOAuthRuntime as i, createNoopRecorder as l, assertRestResourceBinding as n, assertResourcePathShape as o, methodNotAllowed as p, createRequestAuthorizer as r, resolveProtectedResource as s, evaluateCors as t, nowMs as u };
@@ -1,28 +1,7 @@
1
1
  const require_logger = require("./logger-CN1q-KNn.cjs");
2
- const require_package = require("./package-CGLPZwz-.cjs");
2
+ const require_package = require("./package-ClCIqol1.cjs");
3
3
  require("./metadata-path-zd7NSNoa.cjs");
4
4
  let jose = require("jose");
5
- //#region src/core/cors.ts
6
- const EXPOSE_HEADERS = "WWW-Authenticate, Mcp-Session-Id, Mcp-Protocol-Version";
7
- const ALLOW_HEADERS = "Authorization, Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID";
8
- /** Add permissive CORS to a built response, preserving its other headers. */
9
- function withCors(response) {
10
- response.headers.set("Access-Control-Allow-Origin", "*");
11
- response.headers.set("Access-Control-Expose-Headers", EXPOSE_HEADERS);
12
- return response;
13
- }
14
- function corsPreflightResponse(allowMethods) {
15
- return new Response(null, {
16
- status: 204,
17
- headers: {
18
- "Access-Control-Allow-Origin": "*",
19
- "Access-Control-Allow-Methods": allowMethods,
20
- "Access-Control-Allow-Headers": ALLOW_HEADERS,
21
- "Access-Control-Max-Age": "86400"
22
- }
23
- });
24
- }
25
- //#endregion
26
5
  //#region src/core/http.ts
27
6
  const JSON_HEADERS = { "Content-Type": "application/json" };
28
7
  /** Strip the body from a built response, preserving status and headers, for HEAD. */
@@ -34,7 +13,7 @@ function headResponse(response) {
34
13
  });
35
14
  }
36
15
  function finalizeWireResponse(request, response) {
37
- return withCors(request.method === "HEAD" ? headResponse(response) : response);
16
+ return request.method === "HEAD" ? headResponse(response) : response;
38
17
  }
39
18
  function methodNotAllowed(allow) {
40
19
  return new Response(JSON.stringify({ error: "method not allowed" }), {
@@ -74,6 +53,7 @@ function toLogRecord(rec) {
74
53
  if (rec.reqBytes !== void 0) attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
75
54
  if (rec.resBytes !== void 0) attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
76
55
  if (rec.httpMethod !== void 0) attributes.push(strAttr("http.request.method", rec.httpMethod));
56
+ if (rec.protocol !== void 0) attributes.push(strAttr("mcp.protocol", rec.protocol));
77
57
  attributes.push(strAttr("mcp.stack", rec.stack));
78
58
  if (rec.endUserId !== void 0) attributes.push(strAttr("mcp.end_user_id", rec.endUserId));
79
59
  return {
@@ -177,6 +157,7 @@ var BaseMetricRecorder = class {
177
157
  outcome: ev.outcome,
178
158
  durationMs: ev.durationMs,
179
159
  stack: this.stack,
160
+ ...ev.protocol !== void 0 && { protocol: ev.protocol },
180
161
  ...ev.errorText !== void 0 && { errorText: ev.errorText }
181
162
  });
182
163
  if (!this.config.enabled) return;
@@ -959,6 +940,69 @@ function createRequestAuthorizer(mcp, options = {}) {
959
940
  } };
960
941
  }
961
942
  //#endregion
943
+ //#region src/core/cors.ts
944
+ const EXPOSE_HEADERS = "WWW-Authenticate, MCP-Protocol-Version, Mcp-Session-Id";
945
+ const ALLOW_HEADERS = "Authorization, Content-Type, MCP-Protocol-Version, Mcp-Method, Mcp-Name, Mcp-Session-Id, Last-Event-ID";
946
+ const MCP_PARAM_HEADER = /^mcp-param-[!#$%&'*+.^_`|~0-9A-Za-z-]+$/i;
947
+ function appendVary(headers, value) {
948
+ const values = new Set((headers.get("Vary") ?? "").split(",").map((entry) => entry.trim()).filter(Boolean));
949
+ values.add(value);
950
+ headers.set("Vary", [...values].join(", "));
951
+ }
952
+ function addCorsHeaders(response, allowedOrigin, variesByOrigin) {
953
+ if (allowedOrigin !== void 0) {
954
+ response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
955
+ response.headers.set("Access-Control-Expose-Headers", EXPOSE_HEADERS);
956
+ }
957
+ if (variesByOrigin) appendVary(response.headers, "Origin");
958
+ return response;
959
+ }
960
+ function allowedRequestHeaders(request) {
961
+ const allowed = new Map(ALLOW_HEADERS.split(", ").map((header) => [header.toLowerCase(), header]));
962
+ for (const header of (request.headers.get("Access-Control-Request-Headers") ?? "").split(",")) {
963
+ const normalized = header.trim();
964
+ if (MCP_PARAM_HEADER.test(normalized)) allowed.set(normalized.toLowerCase(), normalized);
965
+ }
966
+ return [...allowed.values()].join(", ");
967
+ }
968
+ function evaluateCors(request, allowedOrigins) {
969
+ const origin = request.headers.get("Origin");
970
+ const allowAny = allowedOrigins === "any";
971
+ let allowedOrigin;
972
+ if (allowAny) allowedOrigin = "*";
973
+ else if (origin === null) allowedOrigin = void 0;
974
+ else if (origin === new URL(request.url).origin || allowedOrigins?.includes(origin)) allowedOrigin = origin;
975
+ else allowedOrigin = null;
976
+ if (allowedOrigin === null) {
977
+ const response = Response.json({ error: "origin not allowed" }, {
978
+ status: 403,
979
+ headers: { "Cache-Control": "no-store" }
980
+ });
981
+ appendVary(response.headers, "Origin");
982
+ return {
983
+ ok: false,
984
+ response
985
+ };
986
+ }
987
+ return {
988
+ ok: true,
989
+ withHeaders: (response) => addCorsHeaders(response, allowedOrigin, !allowAny),
990
+ preflight: (allowMethods) => {
991
+ const requestedHeaders = request.headers.get("Access-Control-Request-Headers");
992
+ const response = new Response(null, {
993
+ status: 204,
994
+ headers: {
995
+ "Access-Control-Allow-Methods": allowMethods,
996
+ "Access-Control-Allow-Headers": allowedRequestHeaders(request),
997
+ "Access-Control-Max-Age": "86400"
998
+ }
999
+ });
1000
+ if (requestedHeaders) appendVary(response.headers, "Access-Control-Request-Headers");
1001
+ return addCorsHeaders(response, allowedOrigin, !allowAny);
1002
+ }
1003
+ };
1004
+ }
1005
+ //#endregion
962
1006
  Object.defineProperty(exports, "JSON_HEADERS", {
963
1007
  enumerable: true,
964
1008
  get: function() {
@@ -977,12 +1021,6 @@ Object.defineProperty(exports, "assertRestResourceBinding", {
977
1021
  return assertRestResourceBinding;
978
1022
  }
979
1023
  });
980
- Object.defineProperty(exports, "corsPreflightResponse", {
981
- enumerable: true,
982
- get: function() {
983
- return corsPreflightResponse;
984
- }
985
- });
986
1024
  Object.defineProperty(exports, "createNoopRecorder", {
987
1025
  enumerable: true,
988
1026
  get: function() {
@@ -1001,6 +1039,12 @@ Object.defineProperty(exports, "createRequestAuthorizer", {
1001
1039
  return createRequestAuthorizer;
1002
1040
  }
1003
1041
  });
1042
+ Object.defineProperty(exports, "evaluateCors", {
1043
+ enumerable: true,
1044
+ get: function() {
1045
+ return evaluateCors;
1046
+ }
1047
+ });
1004
1048
  Object.defineProperty(exports, "finalizeWireResponse", {
1005
1049
  enumerable: true,
1006
1050
  get: function() {
@@ -15,9 +15,9 @@
15
15
  * proxy which *overwrites* the header (Lovable's web-proxy does), never by a
16
16
  * bare SDK consumer.
17
17
  * - `X-Forwarded-Proto` only selects http/https, so it is gated separately:
18
- * Supabase terminates TLS upstream and forwards over http with a
19
- * gateway-stamped proto, so that stack always trusts it; the TanStack proxy
20
- * does not sanitize proto, so its Vite plugin never emits the flag.
18
+ * Supabase's gateway stamps it (that stack always trusts it), and Lovable's
19
+ * preview proxy overwrites it before the TanStack dev server, so the TanStack
20
+ * Vite plugin emits the flag by default.
21
21
  */
22
22
  function applyForwardedOrigin(request, options) {
23
23
  const proto = options.trustForwardedProto ? firstForwardedValue(request, "x-forwarded-proto") : void 0;
@@ -15,9 +15,9 @@
15
15
  * proxy which *overwrites* the header (Lovable's web-proxy does), never by a
16
16
  * bare SDK consumer.
17
17
  * - `X-Forwarded-Proto` only selects http/https, so it is gated separately:
18
- * Supabase terminates TLS upstream and forwards over http with a
19
- * gateway-stamped proto, so that stack always trusts it; the TanStack proxy
20
- * does not sanitize proto, so its Vite plugin never emits the flag.
18
+ * Supabase's gateway stamps it (that stack always trusts it), and Lovable's
19
+ * preview proxy overwrites it before the TanStack dev server, so the TanStack
20
+ * Vite plugin emits the flag by default.
21
21
  */
22
22
  function applyForwardedOrigin(request, options) {
23
23
  const proto = options.trustForwardedProto ? firstForwardedValue(request, "x-forwarded-proto") : void 0;
@@ -1,4 +1,4 @@
1
- const require_authorize = require("./authorize-ChY44o_1.cjs");
1
+ const require_cors = require("./cors-BRv5KXKQ.cjs");
2
2
  //#region src/protocols/gate.ts
3
3
  function createGatedHandler(gate) {
4
4
  const allow = [...gate.methods, "OPTIONS"].join(", ");
@@ -8,9 +8,11 @@ function createGatedHandler(gate) {
8
8
  if (!gate.methods.includes(request.method)) return gate.methodNotAllowed(allow);
9
9
  return gate.handle(request, authResult, recorder, ...extra);
10
10
  };
11
- return async (request, recorder = require_authorize.createNoopRecorder(), ...extra) => {
12
- if (request.method === "OPTIONS") return require_authorize.corsPreflightResponse(allow);
13
- const final = require_authorize.finalizeWireResponse(request, await respond(request, recorder, ...extra));
11
+ return async (request, recorder = require_cors.createNoopRecorder(), ...extra) => {
12
+ const cors = require_cors.evaluateCors(request, gate.allowedOrigins);
13
+ if (!cors.ok) return require_cors.finalizeWireResponse(request, cors.response);
14
+ if (request.method === "OPTIONS") return cors.preflight(allow);
15
+ const final = require_cors.finalizeWireResponse(request, cors.withHeaders(await respond(request, recorder, ...extra)));
14
16
  if (!final.headers.has("Cache-Control")) final.headers.set("Cache-Control", "no-store");
15
17
  return final;
16
18
  };
@@ -1,4 +1,4 @@
1
- import { c as createNoopRecorder, d as finalizeWireResponse, p as corsPreflightResponse } from "./authorize--rUeMOGU.js";
1
+ import { f as finalizeWireResponse, l as createNoopRecorder, t as evaluateCors } from "./cors-BDTQQJE2.js";
2
2
  //#region src/protocols/gate.ts
3
3
  function createGatedHandler(gate) {
4
4
  const allow = [...gate.methods, "OPTIONS"].join(", ");
@@ -9,8 +9,10 @@ function createGatedHandler(gate) {
9
9
  return gate.handle(request, authResult, recorder, ...extra);
10
10
  };
11
11
  return async (request, recorder = createNoopRecorder(), ...extra) => {
12
- if (request.method === "OPTIONS") return corsPreflightResponse(allow);
13
- const final = finalizeWireResponse(request, await respond(request, recorder, ...extra));
12
+ const cors = evaluateCors(request, gate.allowedOrigins);
13
+ if (!cors.ok) return finalizeWireResponse(request, cors.response);
14
+ if (request.method === "OPTIONS") return cors.preflight(allow);
15
+ const final = finalizeWireResponse(request, cors.withHeaders(await respond(request, recorder, ...extra)));
14
16
  if (!final.headers.has("Cache-Control")) final.headers.set("Cache-Control", "no-store");
15
17
  return final;
16
18
  };
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_logger = require("./logger-CN1q-KNn.cjs");
3
+ const require_schema = require("./schema-D3vClxb7.cjs");
3
4
  const require_errors = require("./errors-CN6Da8iz.cjs");
4
5
  //#region src/core/define.ts
5
6
  function assertUniqueNames(mcp) {
@@ -79,6 +80,39 @@ function freezeAuth(auth) {
79
80
  if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
80
81
  Object.freeze(auth);
81
82
  }
83
+ function assertAllowedOrigins(allowedOrigins) {
84
+ if (allowedOrigins === void 0 || allowedOrigins === "any") return;
85
+ if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
86
+ for (const origin of allowedOrigins) {
87
+ if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
88
+ let parsed;
89
+ try {
90
+ parsed = new URL(origin);
91
+ } catch {
92
+ throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
93
+ }
94
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
95
+ }
96
+ }
97
+ function assertToolSchemas(mcp) {
98
+ for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
99
+ "inputSchema",
100
+ tool.inputSchema,
101
+ "input"
102
+ ], [
103
+ "outputSchema",
104
+ tool.outputSchema,
105
+ "output"
106
+ ]]) {
107
+ if (!definition) continue;
108
+ try {
109
+ require_schema.jsonSchemaFromDefinition(definition, strategy);
110
+ } catch (error) {
111
+ const detail = error instanceof Error ? `: ${error.message}` : "";
112
+ throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
113
+ }
114
+ }
115
+ }
82
116
  /**
83
117
  * Declare a single MCP tool. Import the result into your MCP definition's
84
118
  * `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
@@ -101,8 +135,11 @@ function defineMcp(def) {
101
135
  assertNonEmptyString("version", def.version);
102
136
  assertUniqueNames(def);
103
137
  if (def.auth) assertOAuthConfig(def.auth);
138
+ assertAllowedOrigins(def.allowedOrigins);
139
+ assertToolSchemas(def);
104
140
  require_logger.resolveMetricsConfig(def.metrics);
105
141
  freezeAuth(def.auth);
142
+ if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
106
143
  Object.freeze(def.tools);
107
144
  for (const tool of def.tools) Object.freeze(tool);
108
145
  return def;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as McpAuthConfig, S as JwtClaims, _ as ZodRawShape, a as EmbeddedResource, b as MetricsOptions, c as McpDefinition, d as ResourceLinkIcon, f as TextContent, g as ToolHandlerResult, h as ToolDefinition, i as EmbeddedBlobResource, l as McpDefinitionInput, m as ToolContent, n as ContentAnnotations, o as EmbeddedTextResource, p as ToolAnnotations, r as ContentBlock, s as ImageContent, t as AudioContent, u as ResourceLink, v as ZodSchema, x as ToolContext, y as MetricsConfig } from "./types-C0Wgm9zp.cjs";
1
+ import { C as MetricsOptions, E as McpAuthConfig, S as MetricsConfig, T as JwtClaims, _ as ToolDefinition, a as EmbeddedResource, b as ZodRawShape, c as JsonValue, d as McpDefinitionInput, f as ResourceLink, g as ToolContent, h as ToolAnnotations, i as EmbeddedBlobResource, l as McpAllowedOrigins, m as TextContent, n as ContentAnnotations, o as EmbeddedTextResource, p as ResourceLinkIcon, r as ContentBlock, s as ImageContent, t as AudioContent, u as McpDefinition, v as ToolHandlerResult, w as ToolContext, x as ZodSchema, y as ZodOutputSchema } from "./types-D1cgsnPu.cjs";
2
2
  //#region src/core/define.d.ts
3
3
  /**
4
4
  * Declare a single MCP tool. Import the result into your MCP definition's
@@ -8,7 +8,7 @@ import { C as McpAuthConfig, S as JwtClaims, _ as ZodRawShape, a as EmbeddedReso
8
8
  * full `z.object(...)` — the MCP SDK builds the object wrapper internally
9
9
  * and the raw shape is what the JSON-RPC `tools/list` payload exposes.
10
10
  */
11
- declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodRawShape | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
11
+ declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
12
12
  /**
13
13
  * Declare the MCP server. `export default` the result from your MCP
14
14
  * entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
@@ -71,4 +71,4 @@ type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
71
71
  */
72
72
  declare function setLogLevel(level: LogLevel): LogLevel;
73
73
  //#endregion
74
- export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JwtClaims, type LogLevel, type McpDefinitionInput, type MetricsConfig, type MetricsOptions, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
74
+ export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpDefinitionInput, type MetricsConfig, type MetricsOptions, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as McpAuthConfig, S as JwtClaims, _ as ZodRawShape, a as EmbeddedResource, b as MetricsOptions, c as McpDefinition, d as ResourceLinkIcon, f as TextContent, g as ToolHandlerResult, h as ToolDefinition, i as EmbeddedBlobResource, l as McpDefinitionInput, m as ToolContent, n as ContentAnnotations, o as EmbeddedTextResource, p as ToolAnnotations, r as ContentBlock, s as ImageContent, t as AudioContent, u as ResourceLink, v as ZodSchema, x as ToolContext, y as MetricsConfig } from "./types-C0Wgm9zp.js";
1
+ import { C as MetricsOptions, E as McpAuthConfig, S as MetricsConfig, T as JwtClaims, _ as ToolDefinition, a as EmbeddedResource, b as ZodRawShape, c as JsonValue, d as McpDefinitionInput, f as ResourceLink, g as ToolContent, h as ToolAnnotations, i as EmbeddedBlobResource, l as McpAllowedOrigins, m as TextContent, n as ContentAnnotations, o as EmbeddedTextResource, p as ResourceLinkIcon, r as ContentBlock, s as ImageContent, t as AudioContent, u as McpDefinition, v as ToolHandlerResult, w as ToolContext, x as ZodSchema, y as ZodOutputSchema } from "./types-D1cgsnPu.js";
2
2
  //#region src/core/define.d.ts
3
3
  /**
4
4
  * Declare a single MCP tool. Import the result into your MCP definition's
@@ -8,7 +8,7 @@ import { C as McpAuthConfig, S as JwtClaims, _ as ZodRawShape, a as EmbeddedReso
8
8
  * full `z.object(...)` — the MCP SDK builds the object wrapper internally
9
9
  * and the raw shape is what the JSON-RPC `tools/list` payload exposes.
10
10
  */
11
- declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodRawShape | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
11
+ declare function defineTool<TInput extends ZodRawShape | undefined = undefined, TOutput extends ZodOutputSchema | undefined = undefined>(def: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
12
12
  /**
13
13
  * Declare the MCP server. `export default` the result from your MCP
14
14
  * entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
@@ -71,4 +71,4 @@ type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
71
71
  */
72
72
  declare function setLogLevel(level: LogLevel): LogLevel;
73
73
  //#endregion
74
- export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JwtClaims, type LogLevel, type McpDefinitionInput, type MetricsConfig, type MetricsOptions, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
74
+ export { type AudioContent, type ContentAnnotations, type ContentBlock, type EmbeddedBlobResource, type EmbeddedResource, type EmbeddedTextResource, type ImageContent, type IssuerOAuthOptions, type JsonValue, type JwtClaims, type LogLevel, type McpAllowedOrigins, type McpDefinitionInput, type MetricsConfig, type MetricsOptions, type ResourceLink, type ResourceLinkIcon, type TextContent, type ToolAnnotations, type ToolContent, ToolContext, type ToolDefinition, ToolError, type ToolHandlerResult, type ZodOutputSchema, type ZodRawShape, type ZodSchema, auth, defineMcp, defineTool, setLogLevel };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { a as setLogLevel, o as parseSafeUrl, s as trimTrailingSlash, u as resolveMetricsConfig } from "./logger-Ctv5xUSD.js";
2
+ import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
2
3
  import { i as ToolContext, t as ToolError } from "./errors-DSe96Ffd.js";
3
4
  //#region src/core/define.ts
4
5
  function assertUniqueNames(mcp) {
@@ -78,6 +79,39 @@ function freezeAuth(auth) {
78
79
  if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
79
80
  Object.freeze(auth);
80
81
  }
82
+ function assertAllowedOrigins(allowedOrigins) {
83
+ if (allowedOrigins === void 0 || allowedOrigins === "any") return;
84
+ if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
85
+ for (const origin of allowedOrigins) {
86
+ if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
87
+ let parsed;
88
+ try {
89
+ parsed = new URL(origin);
90
+ } catch {
91
+ throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
92
+ }
93
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
94
+ }
95
+ }
96
+ function assertToolSchemas(mcp) {
97
+ for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
98
+ "inputSchema",
99
+ tool.inputSchema,
100
+ "input"
101
+ ], [
102
+ "outputSchema",
103
+ tool.outputSchema,
104
+ "output"
105
+ ]]) {
106
+ if (!definition) continue;
107
+ try {
108
+ jsonSchemaFromDefinition(definition, strategy);
109
+ } catch (error) {
110
+ const detail = error instanceof Error ? `: ${error.message}` : "";
111
+ throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
112
+ }
113
+ }
114
+ }
81
115
  /**
82
116
  * Declare a single MCP tool. Import the result into your MCP definition's
83
117
  * `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
@@ -100,8 +134,11 @@ function defineMcp(def) {
100
134
  assertNonEmptyString("version", def.version);
101
135
  assertUniqueNames(def);
102
136
  if (def.auth) assertOAuthConfig(def.auth);
137
+ assertAllowedOrigins(def.allowedOrigins);
138
+ assertToolSchemas(def);
103
139
  resolveMetricsConfig(def.metrics);
104
140
  freezeAuth(def.auth);
141
+ if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
105
142
  Object.freeze(def.tools);
106
143
  for (const tool of def.tools) Object.freeze(tool);
107
144
  return def;
@@ -1,4 +1,4 @@
1
- import "./list-tools-BAqQVIHk.js";
1
+ import "./list-tools-DXqSPvNY.js";
2
2
  //#region src/manifest/io.d.ts
3
3
  /**
4
4
  * Shape every MCP Vite plugin exposes on its `api` so `runExtract` can read
@@ -1,4 +1,4 @@
1
- import "./list-tools-BN97L2Yv.cjs";
1
+ import "./list-tools-C3AoI2Zw.cjs";
2
2
  //#region src/manifest/io.d.ts
3
3
  /**
4
4
  * Shape every MCP Vite plugin exposes on its `api` so `runExtract` can read
@@ -1,15 +1,10 @@
1
- import { f as methodNotAllowed, n as createRequestAuthorizer, t as assertRestResourceBinding } from "./authorize--rUeMOGU.js";
2
- import { t as createGatedHandler } from "./gate-BiM6EBeA.js";
3
- import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
4
- import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";
1
+ import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
2
+ import { n as assertRestResourceBinding, p as methodNotAllowed, r as createRequestAuthorizer } from "./cors-BDTQQJE2.js";
3
+ import { t as createGatedHandler } from "./gate-uCVrbDBb.js";
5
4
  //#region src/protocols/rest/list-tools.ts
6
- function shapeToJsonSchema(shape) {
7
- if (!shape) return null;
8
- try {
9
- return toJsonSchemaCompat(objectFromShape(shape));
10
- } catch {
11
- return null;
12
- }
5
+ function schemaToJsonSchema(definition, pipeStrategy) {
6
+ if (!definition) return null;
7
+ return jsonSchemaFromDefinition(definition, pipeStrategy);
13
8
  }
14
9
  function buildMcpListing(mcp) {
15
10
  return {
@@ -23,8 +18,8 @@ function buildMcpListing(mcp) {
23
18
  title: tool.title,
24
19
  description: tool.description,
25
20
  annotations: tool.annotations,
26
- inputSchema: shapeToJsonSchema(tool.inputSchema),
27
- outputSchema: shapeToJsonSchema(tool.outputSchema)
21
+ inputSchema: schemaToJsonSchema(tool.inputSchema, "input"),
22
+ outputSchema: schemaToJsonSchema(tool.outputSchema, "output")
28
23
  }))
29
24
  };
30
25
  }
@@ -32,6 +27,7 @@ function createListToolsHandler(mcp, options = {}) {
32
27
  assertRestResourceBinding(mcp, options);
33
28
  return createGatedHandler({
34
29
  authorizer: createRequestAuthorizer(mcp, options),
30
+ allowedOrigins: mcp.allowedOrigins,
35
31
  methods: ["GET", "HEAD"],
36
32
  methodNotAllowed,
37
33
  handle: async () => Response.json(buildMcpListing(mcp))