@lovable.dev/mcp-js 0.14.0 → 0.15.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 (38) hide show
  1. package/README.md +28 -0
  2. package/dist/{chunk-YWLMMDET.js → chunk-CEDD57G2.js} +14 -3
  3. package/dist/{chunk-QC3DXQTH.js → chunk-DCWYK4CA.js} +34 -0
  4. package/dist/{chunk-NOFPRSSI.js → chunk-GIHCQT6L.js} +1 -1
  5. package/dist/{chunk-QDKOF4UF.js → chunk-ILYTJXDR.js} +2 -2
  6. package/dist/{chunk-VNRQPA4K.js → chunk-QT5L4CS3.js} +4 -3
  7. package/dist/{chunk-WLNT2FX7.js → chunk-UCPYLSNN.js} +18 -6
  8. package/dist/{chunk-G4XA7IJM.js → chunk-YTOMGJV5.js} +189 -2
  9. package/dist/cli/extract-manifest.cjs +1 -1
  10. package/dist/cli/extract-manifest.js +6 -6
  11. package/dist/index.cjs +33 -0
  12. package/dist/index.d.cts +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +3 -1
  15. package/dist/protocols/mcp/index.cjs +230 -5
  16. package/dist/protocols/mcp/index.d.cts +3 -2
  17. package/dist/protocols/mcp/index.d.ts +3 -2
  18. package/dist/protocols/mcp/index.js +4 -3
  19. package/dist/protocols/oauth-metadata.d.cts +1 -1
  20. package/dist/protocols/oauth-metadata.d.ts +1 -1
  21. package/dist/protocols/oauth-metadata.js +4 -3
  22. package/dist/protocols/rest/index.cjs +229 -5
  23. package/dist/protocols/rest/index.d.cts +4 -3
  24. package/dist/protocols/rest/index.d.ts +4 -3
  25. package/dist/protocols/rest/index.js +5 -4
  26. package/dist/recorder-qlzUKFxG.d.ts +21 -0
  27. package/dist/stacks/supabase/index.cjs +263 -28
  28. package/dist/stacks/supabase/index.d.cts +1 -1
  29. package/dist/stacks/supabase/index.d.ts +1 -1
  30. package/dist/stacks/supabase/index.js +13 -10
  31. package/dist/stacks/supabase/vite.cjs +28 -4
  32. package/dist/stacks/supabase/vite.js +30 -6
  33. package/dist/stacks/tanstack/index.cjs +243 -9
  34. package/dist/stacks/tanstack/index.d.cts +1 -1
  35. package/dist/stacks/tanstack/index.d.ts +1 -1
  36. package/dist/stacks/tanstack/index.js +7 -6
  37. package/dist/{types-BanzncFh.d.ts → types-COY42xux.d.ts} +30 -1
  38. package/package.json +1 -1
@@ -1,11 +1,12 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
- import { d as McpDefinition } from '../../types-BanzncFh.js';
2
+ import { d as McpDefinition } from '../../types-COY42xux.js';
3
+ import { M as MetricsRecorder } from '../../recorder-qlzUKFxG.js';
3
4
  import 'zod';
4
5
 
5
6
  type RestListToolsHandler = (request: Request) => Promise<Response>;
6
- declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestListToolsHandler;
7
+ declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestListToolsHandler;
7
8
 
8
9
  type RestInvokeToolHandler = (request: Request, toolName: string) => Promise<Response>;
9
- declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestInvokeToolHandler;
10
+ declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestInvokeToolHandler;
10
11
 
11
12
  export { type RestInvokeToolHandler, type RestListToolsHandler, createInvokeToolHandler, createListToolsHandler };
@@ -1,13 +1,14 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-YWLMMDET.js";
3
+ } from "../../chunk-CEDD57G2.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-VNRQPA4K.js";
6
+ } from "../../chunk-QT5L4CS3.js";
7
7
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-G4XA7IJM.js";
9
- import "../../chunk-QC3DXQTH.js";
8
+ import "../../chunk-YTOMGJV5.js";
9
+ import "../../chunk-DCWYK4CA.js";
10
10
  import "../../chunk-6DXGZZA4.js";
11
+ import "../../chunk-GIHCQT6L.js";
11
12
  export {
12
13
  createInvokeToolHandler,
13
14
  createListToolsHandler
@@ -0,0 +1,21 @@
1
+ type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_config_error";
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. */
4
+ interface InvocationRecord {
5
+ /** Tool name for `tools/call`; `null` for list/initialize, transport faults, and auth-config failures. */
6
+ tool: string | null;
7
+ /** JSON-RPC method, e.g. `tools/call`; `authorize` for auth-config failures. */
8
+ method: string;
9
+ outcome: InvocationOutcome;
10
+ durationMs: number;
11
+ reqBytes?: number;
12
+ resBytes?: number;
13
+ }
14
+ interface MetricsRecorder {
15
+ /** Buffer one invocation. Synchronous, sampled, and never throws. */
16
+ record(ev: InvocationRecord): void;
17
+ /** Best-effort POST of the current buffer. Resolves even on network failure. */
18
+ flush(): Promise<void>;
19
+ }
20
+
21
+ export type { MetricsRecorder as M };
@@ -95,22 +95,6 @@ function firstForwardedValue(request, header) {
95
95
  return value ? value : void 0;
96
96
  }
97
97
 
98
- // src/protocols/mcp/protocol.ts
99
- var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
100
- var import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
101
-
102
- // src/core/http.ts
103
- var JSON_HEADERS = { "Content-Type": "application/json" };
104
- function headResponse(response) {
105
- return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers });
106
- }
107
- function methodNotAllowed(allow) {
108
- return new Response(JSON.stringify({ error: "method not allowed" }), {
109
- status: 405,
110
- headers: { ...JSON_HEADERS, Allow: allow }
111
- });
112
- }
113
-
114
98
  // src/core/logger.ts
115
99
  var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
116
100
  function isLogLevel(value) {
@@ -152,6 +136,230 @@ function describeError(err) {
152
136
  return { value: String(err) };
153
137
  }
154
138
 
139
+ // src/metrics/config.ts
140
+ var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
141
+ var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
142
+ var METRICS_SAMPLE_RATE = 1;
143
+ var METRICS_FLUSH_INTERVAL_MS = 5e3;
144
+ var METRICS_MAX_BATCH_SIZE = 50;
145
+ function assertMetricsEndpoint(endpoint) {
146
+ let url;
147
+ try {
148
+ url = new URL(endpoint);
149
+ } catch {
150
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
151
+ }
152
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
153
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
154
+ }
155
+ }
156
+ function resolveMetricsConfig(config = true) {
157
+ const options = typeof config === "boolean" ? { enabled: config } : config;
158
+ const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
159
+ assertMetricsEndpoint(endpoint);
160
+ return Object.freeze({
161
+ enabled: options.enabled ?? true,
162
+ endpoint,
163
+ headers: options.headers ?? {},
164
+ apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
165
+ sampleRate: METRICS_SAMPLE_RATE,
166
+ flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
167
+ maxBatchSize: METRICS_MAX_BATCH_SIZE
168
+ });
169
+ }
170
+
171
+ // package.json
172
+ var version = "0.15.1";
173
+
174
+ // src/metrics/otlp.ts
175
+ var SCOPE_NAME = "@lovable.dev/mcp-js";
176
+ var EVENT_NAME = "mcp.tool.invocation";
177
+ var SEVERITY_INFO = 9;
178
+ function strAttr(key, value) {
179
+ return { key, value: { stringValue: value } };
180
+ }
181
+ function intAttr(key, value) {
182
+ return { key, value: { intValue: String(Math.round(value)) } };
183
+ }
184
+ function toLogRecord(rec) {
185
+ const attributes = [
186
+ strAttr("event.name", EVENT_NAME),
187
+ strAttr("mcp.method", rec.method),
188
+ strAttr("mcp.outcome", rec.outcome),
189
+ intAttr("mcp.duration_ms", rec.durationMs)
190
+ ];
191
+ if (rec.tool !== null)
192
+ attributes.push(strAttr("mcp.tool", rec.tool));
193
+ if (rec.reqBytes !== void 0)
194
+ attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
195
+ if (rec.resBytes !== void 0)
196
+ attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
197
+ return {
198
+ timeUnixNano: rec.timeUnixNano,
199
+ observedTimeUnixNano: rec.timeUnixNano,
200
+ severityNumber: SEVERITY_INFO,
201
+ severityText: "INFO",
202
+ body: { stringValue: EVENT_NAME },
203
+ attributes
204
+ };
205
+ }
206
+ function buildLogsPayload(records, server) {
207
+ return JSON.stringify({
208
+ resourceLogs: [
209
+ {
210
+ resource: {
211
+ attributes: [
212
+ strAttr("service.name", server.name),
213
+ strAttr("service.version", server.version),
214
+ strAttr("telemetry.sdk.name", SCOPE_NAME),
215
+ strAttr("telemetry.sdk.version", version),
216
+ strAttr("telemetry.sdk.language", "webjs")
217
+ ]
218
+ },
219
+ scopeLogs: [
220
+ {
221
+ scope: { name: SCOPE_NAME, version },
222
+ logRecords: records.map(toLogRecord)
223
+ }
224
+ ]
225
+ }
226
+ ]
227
+ });
228
+ }
229
+ function nowUnixNano() {
230
+ return `${Date.now()}000000`;
231
+ }
232
+
233
+ // src/metrics/recorder.ts
234
+ function nowMs() {
235
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
236
+ }
237
+ var NOOP_RECORDER = {
238
+ record() {
239
+ },
240
+ async flush() {
241
+ }
242
+ };
243
+ function createNoopRecorder() {
244
+ return NOOP_RECORDER;
245
+ }
246
+ function readRuntimeEnv(name) {
247
+ try {
248
+ const denoEnv = globalThis.Deno?.env;
249
+ const value = denoEnv?.get?.(name);
250
+ if (value)
251
+ return value;
252
+ } catch {
253
+ }
254
+ try {
255
+ if (typeof process !== "undefined") {
256
+ const value = process.env?.[name];
257
+ if (value)
258
+ return value;
259
+ }
260
+ } catch {
261
+ }
262
+ return void 0;
263
+ }
264
+ function probeWaitUntil() {
265
+ const fn = globalThis.EdgeRuntime?.waitUntil;
266
+ return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
267
+ }
268
+ function createMetricsRecorder(ctx, deps = {}) {
269
+ const { config, server } = ctx;
270
+ if (!config.enabled)
271
+ return NOOP_RECORDER;
272
+ const doFetch = deps.fetch ?? globalThis.fetch;
273
+ if (!doFetch)
274
+ return NOOP_RECORDER;
275
+ const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
276
+ const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
277
+ if (usesLovableEndpoint && !apiKey) {
278
+ log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
279
+ return NOOP_RECORDER;
280
+ }
281
+ const waitUntil = deps.waitUntil ?? probeWaitUntil();
282
+ const buffer = [];
283
+ let timer;
284
+ const schedule = (p) => {
285
+ if (waitUntil) {
286
+ try {
287
+ waitUntil(p);
288
+ return;
289
+ } catch {
290
+ }
291
+ }
292
+ void p.catch(() => {
293
+ });
294
+ };
295
+ const headers = {};
296
+ if (!usesLovableEndpoint) {
297
+ for (const [key, value] of Object.entries(config.headers)) {
298
+ if (key.toLowerCase() !== "content-type")
299
+ headers[key] = value;
300
+ }
301
+ }
302
+ headers["content-type"] = "application/json";
303
+ if (apiKey)
304
+ headers.authorization = `Bearer ${apiKey}`;
305
+ const flush = async () => {
306
+ if (buffer.length === 0)
307
+ return;
308
+ const records = buffer.splice(0, buffer.length);
309
+ try {
310
+ const res = await doFetch(config.endpoint, {
311
+ method: "POST",
312
+ headers,
313
+ body: buildLogsPayload(records, server),
314
+ keepalive: true
315
+ });
316
+ if (!res.ok)
317
+ log.debug("metrics.flush_rejected", { status: res.status });
318
+ } catch (err) {
319
+ log.debug("metrics.flush_failed", describeError(err));
320
+ }
321
+ };
322
+ const ensureTimer = () => {
323
+ if (timer !== void 0)
324
+ return;
325
+ timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
326
+ timer.unref?.();
327
+ };
328
+ return {
329
+ record(ev) {
330
+ if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
331
+ return;
332
+ buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
333
+ ensureTimer();
334
+ if (buffer.length >= config.maxBatchSize)
335
+ schedule(flush());
336
+ },
337
+ flush
338
+ };
339
+ }
340
+ function createRecorderForRuntime(mcp) {
341
+ const config = resolveMetricsConfig(mcp.metrics);
342
+ if (!config.enabled)
343
+ return createNoopRecorder();
344
+ return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
345
+ }
346
+
347
+ // src/protocols/mcp/protocol.ts
348
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
349
+ var import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
350
+
351
+ // src/core/http.ts
352
+ var JSON_HEADERS = { "Content-Type": "application/json" };
353
+ function headResponse(response) {
354
+ return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers });
355
+ }
356
+ function methodNotAllowed(allow) {
357
+ return new Response(JSON.stringify({ error: "method not allowed" }), {
358
+ status: 405,
359
+ headers: { ...JSON_HEADERS, Allow: allow }
360
+ });
361
+ }
362
+
155
363
  // src/core/promise.ts
156
364
  function cachedPromise(load, label) {
157
365
  let settled = false;
@@ -532,12 +740,13 @@ function assertRequiredScopes(auth, context) {
532
740
  throw new OAuthTokenError(403, "insufficient_scope", "Additional OAuth scope is required");
533
741
  }
534
742
  }
535
- function createRequestAuthorizer(mcp, options = {}) {
743
+ function createRequestAuthorizer(mcp, options = {}, recorder) {
536
744
  const runtime = getOAuthRuntime(mcp, options);
537
745
  return {
538
746
  async authorize(request) {
539
747
  if (runtime.kind === "unconfigured")
540
748
  return { ok: true };
749
+ const startedAt = nowMs();
541
750
  const token = parseBearerToken(request);
542
751
  if (!token) {
543
752
  log.info("auth.no_bearer_token", { outcome: "401" });
@@ -550,6 +759,12 @@ function createRequestAuthorizer(mcp, options = {}) {
550
759
  } catch (err) {
551
760
  if (err instanceof OAuthConfigurationError) {
552
761
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
762
+ recorder?.record({
763
+ tool: null,
764
+ method: "authorize",
765
+ outcome: "auth_config_error",
766
+ durationMs: nowMs() - startedAt
767
+ });
553
768
  return { ok: false, response: oauthConfigurationErrorResponse() };
554
769
  }
555
770
  if (err instanceof OAuthTokenError) {
@@ -647,23 +862,32 @@ function corsPreflightResponse(allowMethods) {
647
862
  }
648
863
 
649
864
  // src/protocols/mcp/protocol.ts
650
- function adaptToolToSdkCallback(tool, auth) {
865
+ function adaptToolToSdkCallback(tool, auth, recorder) {
651
866
  return async (first) => {
652
867
  const args = tool.inputSchema ? first ?? {} : {};
868
+ const start = nowMs();
653
869
  let result;
654
870
  try {
655
871
  result = await tool.handler(args, new ToolContext(auth));
656
872
  } catch {
873
+ recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
657
874
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
658
875
  }
659
876
  if (result == null) {
877
+ recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
660
878
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
661
879
  }
880
+ recorder.record({
881
+ tool: tool.name,
882
+ method: "tools/call",
883
+ outcome: result.isError ? "tool_error" : "ok",
884
+ durationMs: nowMs() - start
885
+ });
662
886
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
663
887
  };
664
888
  }
665
- function createMcpProtocolHandler(mcp, options = {}) {
666
- const authorizer = createRequestAuthorizer(mcp, options);
889
+ function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
890
+ const authorizer = createRequestAuthorizer(mcp, options, recorder);
667
891
  const handle = async (request) => {
668
892
  const authResult = await authorizer.authorize(request);
669
893
  if (!authResult.ok)
@@ -683,7 +907,7 @@ function createMcpProtocolHandler(mcp, options = {}) {
683
907
  outputSchema: tool.outputSchema,
684
908
  annotations: tool.annotations
685
909
  },
686
- adaptToolToSdkCallback(tool, authResult.auth)
910
+ adaptToolToSdkCallback(tool, authResult.auth, recorder)
687
911
  );
688
912
  }
689
913
  const transport = new import_webStandardStreamableHttp.WebStandardStreamableHTTPServerTransport({
@@ -692,6 +916,7 @@ function createMcpProtocolHandler(mcp, options = {}) {
692
916
  await server.connect(transport);
693
917
  return await transport.handleRequest(request);
694
918
  } catch (err) {
919
+ recorder.record({ tool: null, method: "transport", outcome: "transport_error", durationMs: 0 });
695
920
  log.error("mcp.transport_error", { ...describeError(err), outcome: "500 internal error" });
696
921
  return Response.json(
697
922
  { jsonrpc: "2.0", id: null, error: { code: -32603, message: "internal error" } },
@@ -792,9 +1017,9 @@ function buildMcpListing(mcp) {
792
1017
  }))
793
1018
  };
794
1019
  }
795
- function createListToolsHandler(mcp, options = {}) {
1020
+ function createListToolsHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
796
1021
  assertRestResourceBinding(mcp, options);
797
- const authorizer = createRequestAuthorizer(mcp, options);
1022
+ const authorizer = createRequestAuthorizer(mcp, options, recorder);
798
1023
  const handle = async (request) => {
799
1024
  const authResult = await authorizer.authorize(request);
800
1025
  if (!authResult.ok)
@@ -825,9 +1050,9 @@ function isEmptyArgs(value) {
825
1050
  return false;
826
1051
  return Object.keys(value).length === 0;
827
1052
  }
828
- function createInvokeToolHandler(mcp, options = {}) {
1053
+ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
829
1054
  assertRestResourceBinding(mcp, options);
830
- const authorizer = createRequestAuthorizer(mcp, options);
1055
+ const authorizer = createRequestAuthorizer(mcp, options, recorder);
831
1056
  const handle = async (request, toolName) => {
832
1057
  const authResult = await authorizer.authorize(request);
833
1058
  if (!authResult.ok)
@@ -881,20 +1106,29 @@ function createInvokeToolHandler(mcp, options = {}) {
881
1106
  });
882
1107
  }
883
1108
  let result;
1109
+ const start = nowMs();
884
1110
  try {
885
1111
  result = await tool.handler(args, new ToolContext(authResult.auth));
886
1112
  } catch {
1113
+ recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
887
1114
  return new Response(JSON.stringify({ error: "handler threw", tool: toolName }), {
888
1115
  status: 500,
889
1116
  headers: JSON_HEADERS
890
1117
  });
891
1118
  }
892
1119
  if (result == null) {
1120
+ recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
893
1121
  return new Response(JSON.stringify({ error: `tool "${toolName}" returned no result` }), {
894
1122
  status: 500,
895
1123
  headers: JSON_HEADERS
896
1124
  });
897
1125
  }
1126
+ recorder.record({
1127
+ tool: tool.name,
1128
+ method: "tools/call",
1129
+ outcome: result.isError ? "tool_error" : "ok",
1130
+ durationMs: nowMs() - start
1131
+ });
898
1132
  return Response.json({
899
1133
  content: result.content ?? [],
900
1134
  structuredContent: result.structuredContent,
@@ -954,9 +1188,10 @@ function createSupabaseHandler(mcp, options = {}) {
954
1188
  const servesOwnPrm = !(mcp.auth?.type === "oauth" && mcp.auth.protectedResourceMetadataUrl !== void 0);
955
1189
  const metadataPath = resourcePath === void 0 || !servesOwnPrm ? void 0 : `${trimTrailingSlash(resourcePath)}${OAUTH_PROTECTED_RESOURCE_METADATA_PATH}`;
956
1190
  const runtimeOptions = resourcePath === void 0 ? {} : { resourcePath, ...metadataPath ? { metadataPath } : {} };
957
- const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions);
958
- const listToolsHandler = createListToolsHandler(mcp, runtimeOptions);
959
- const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
1191
+ const recorder = createRecorderForRuntime(mcp);
1192
+ const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions, recorder);
1193
+ const listToolsHandler = createListToolsHandler(mcp, runtimeOptions, recorder);
1194
+ const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions, recorder);
960
1195
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
961
1196
  return async (request) => {
962
1197
  const req = applyForwardedOrigin(request, {
@@ -1,4 +1,4 @@
1
- import { d as McpDefinition } from '../../types-BanzncFh.js';
1
+ import { d as McpDefinition } from '../../types-COY42xux.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-BanzncFh.js';
1
+ import { d as McpDefinition } from '../../types-COY42xux.js';
2
2
  import 'zod';
3
3
 
4
4
  type SupabaseHandler = (request: Request) => Promise<Response>;
@@ -3,23 +3,24 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-WLNT2FX7.js";
6
+ } from "../../chunk-UCPYLSNN.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-QDKOF4UF.js";
9
+ } from "../../chunk-ILYTJXDR.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-YWLMMDET.js";
12
+ } from "../../chunk-CEDD57G2.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-VNRQPA4K.js";
15
+ } from "../../chunk-QT5L4CS3.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
17
  import {
18
- assertResourcePathShape
19
- } from "../../chunk-G4XA7IJM.js";
18
+ assertResourcePathShape,
19
+ createRecorderForRuntime
20
+ } from "../../chunk-YTOMGJV5.js";
20
21
  import {
21
22
  trimTrailingSlash
22
- } from "../../chunk-QC3DXQTH.js";
23
+ } from "../../chunk-DCWYK4CA.js";
23
24
  import {
24
25
  OAUTH_PROTECTED_RESOURCE_METADATA_PATH
25
26
  } from "../../chunk-6DXGZZA4.js";
@@ -27,6 +28,7 @@ import {
27
28
  FUNCTIONS_MOUNT_PREFIX,
28
29
  assertFunctionName
29
30
  } from "../../chunk-XQWJN6DC.js";
31
+ import "../../chunk-GIHCQT6L.js";
30
32
 
31
33
  // src/stacks/supabase/handler.ts
32
34
  function deriveResourcePath(options) {
@@ -64,9 +66,10 @@ function createSupabaseHandler(mcp, options = {}) {
64
66
  const servesOwnPrm = !(mcp.auth?.type === "oauth" && mcp.auth.protectedResourceMetadataUrl !== void 0);
65
67
  const metadataPath = resourcePath === void 0 || !servesOwnPrm ? void 0 : `${trimTrailingSlash(resourcePath)}${OAUTH_PROTECTED_RESOURCE_METADATA_PATH}`;
66
68
  const runtimeOptions = resourcePath === void 0 ? {} : { resourcePath, ...metadataPath ? { metadataPath } : {} };
67
- const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions);
68
- const listToolsHandler = createListToolsHandler(mcp, runtimeOptions);
69
- const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
69
+ const recorder = createRecorderForRuntime(mcp);
70
+ const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions, recorder);
71
+ const listToolsHandler = createListToolsHandler(mcp, runtimeOptions, recorder);
72
+ const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions, recorder);
70
73
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
71
74
  return async (request) => {
72
75
  const req = applyForwardedOrigin(request, {
@@ -25,6 +25,7 @@ __export(vite_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(vite_exports);
27
27
  var import_node_path2 = require("path");
28
+ var import_vite = require("vite");
28
29
 
29
30
  // src/stacks/supabase/emit.ts
30
31
  var import_esbuild = require("esbuild");
@@ -32,7 +33,7 @@ var import_node_fs = require("fs");
32
33
  var import_node_path = require("path");
33
34
 
34
35
  // package.json
35
- var version = "0.14.0";
36
+ var version = "0.15.1";
36
37
 
37
38
  // src/core/fs-errors.ts
38
39
  function isFileMissing(err) {
@@ -129,7 +130,16 @@ function externalizeBareAsNpm(versions) {
129
130
  }
130
131
  };
131
132
  }
132
- async function bundleFunctionEntry(projectRoot, mcpEntryAbs, functionName) {
133
+ function importMetaEnvDefines(inlineEnv) {
134
+ const env = inlineEnv ?? {};
135
+ const defines = { "import.meta.env": JSON.stringify(env) };
136
+ for (const [key, value] of Object.entries(env)) {
137
+ if (/^[A-Za-z_$][\w$]*$/.test(key))
138
+ defines[`import.meta.env.${key}`] = JSON.stringify(value);
139
+ }
140
+ return defines;
141
+ }
142
+ async function bundleFunctionEntry(projectRoot, mcpEntryAbs, functionName, inlineEnv) {
133
143
  const versions = readProjectDependencyVersions(projectRoot);
134
144
  const wrapper = `import mcp from ${JSON.stringify(mcpEntryAbs)};
135
145
  import { createSupabaseHandler } from "@lovable.dev/mcp-js/stacks/supabase";
@@ -145,6 +155,7 @@ Deno.serve(createSupabaseHandler(mcp, { functionName: ${JSON.stringify(functionN
145
155
  target: "esnext",
146
156
  absWorkingDir: projectRoot,
147
157
  logLevel: "silent",
158
+ define: importMetaEnvDefines(inlineEnv),
148
159
  plugins: [externalizeBareAsNpm(versions)]
149
160
  });
150
161
  const out = result.outputFiles[0]?.text ?? "";
@@ -183,7 +194,7 @@ async function syncSupabaseFunction(options) {
183
194
  cleanupOrphans(paths.functionDir, /* @__PURE__ */ new Set(), removed);
184
195
  return { written, removed, inputs: [] };
185
196
  }
186
- const { code, inputs } = await bundleFunctionEntry(projectRoot, paths.mcpEntryAbs, functionName);
197
+ const { code, inputs } = await bundleFunctionEntry(projectRoot, paths.mcpEntryAbs, functionName, options.inlineEnv);
187
198
  if (writeIfChanged(paths.functionEntry, code, hasGeneratedBanner)) {
188
199
  written.push(paths.functionEntry);
189
200
  }
@@ -227,6 +238,16 @@ function cleanupOrphans(functionDir, expected, removed) {
227
238
  function normalizePath(p) {
228
239
  return p.split(import_node_path2.sep).join("/");
229
240
  }
241
+ function productionImportMetaEnv(config) {
242
+ return {
243
+ ...(0, import_vite.loadEnv)("production", config.envDir, config.envPrefix),
244
+ MODE: "production",
245
+ BASE_URL: config.base ?? "/",
246
+ DEV: false,
247
+ PROD: true,
248
+ SSR: false
249
+ };
250
+ }
230
251
  function mcpPlugin(options = {}) {
231
252
  const mcpEntryOption = options.mcpEntry ?? DEFAULT_MCP_ENTRY;
232
253
  const functionsDirOption = options.functionsDir ?? DEFAULT_FUNCTIONS_DIR;
@@ -234,13 +255,15 @@ function mcpPlugin(options = {}) {
234
255
  const urlPath = `${FUNCTIONS_MOUNT_PREFIX}${functionName}`;
235
256
  let projectRoot = process.cwd();
236
257
  let mcpEntryAbs = (0, import_node_path2.resolve)(projectRoot, mcpEntryOption);
258
+ let inlineEnv = {};
237
259
  let watchedInputs = /* @__PURE__ */ new Set();
238
260
  const regenerate = async () => {
239
261
  const { inputs } = await syncSupabaseFunction({
240
262
  projectRoot,
241
263
  mcpEntry: mcpEntryOption,
242
264
  functionsDir: functionsDirOption,
243
- functionName
265
+ functionName,
266
+ inlineEnv
244
267
  });
245
268
  watchedInputs = new Set(inputs.map(normalizePath));
246
269
  };
@@ -258,6 +281,7 @@ function mcpPlugin(options = {}) {
258
281
  async configResolved(config) {
259
282
  projectRoot = config.root;
260
283
  mcpEntryAbs = (0, import_node_path2.resolve)(projectRoot, mcpEntryOption);
284
+ inlineEnv = productionImportMetaEnv(config);
261
285
  await regenerate();
262
286
  },
263
287
  configureServer(server) {