@lovable.dev/mcp-js 0.16.0 → 0.19.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 (38) hide show
  1. package/dist/{recorder-qlzUKFxG.d.ts → base-C9rhAHZ0.d.ts} +3 -4
  2. package/dist/{chunk-W2EZWPJ5.js → chunk-57ZH2WW5.js} +11 -12
  3. package/dist/{chunk-H6BKTNJY.js → chunk-5FX6IIQ6.js} +129 -105
  4. package/dist/{chunk-SKSKC747.js → chunk-CDZ7MBXC.js} +1 -1
  5. package/dist/{chunk-EZQVUNXB.js → chunk-CLXKPZZE.js} +13 -14
  6. package/dist/{chunk-DCWYK4CA.js → chunk-H37EB22A.js} +13 -9
  7. package/dist/{chunk-I5CAQUQI.js → chunk-OMWXY6WY.js} +8 -8
  8. package/dist/{chunk-T24Z753F.js → chunk-UEOBGHXF.js} +2 -2
  9. package/dist/cli/extract-manifest.cjs +4 -3
  10. package/dist/cli/extract-manifest.js +4 -4
  11. package/dist/index.cjs +4 -9
  12. package/dist/index.d.cts +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +1 -1
  15. package/dist/protocols/mcp/index.cjs +19 -225
  16. package/dist/protocols/mcp/index.d.cts +6 -5
  17. package/dist/protocols/mcp/index.d.ts +6 -5
  18. package/dist/protocols/mcp/index.js +4 -4
  19. package/dist/protocols/oauth-metadata.cjs +3 -2
  20. package/dist/protocols/oauth-metadata.d.cts +1 -1
  21. package/dist/protocols/oauth-metadata.d.ts +1 -1
  22. package/dist/protocols/oauth-metadata.js +4 -4
  23. package/dist/protocols/rest/index.cjs +24 -230
  24. package/dist/protocols/rest/index.d.cts +6 -6
  25. package/dist/protocols/rest/index.d.ts +6 -6
  26. package/dist/protocols/rest/index.js +5 -5
  27. package/dist/stacks/supabase/index.cjs +196 -169
  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 +14 -14
  31. package/dist/stacks/supabase/vite.cjs +1 -1
  32. package/dist/stacks/supabase/vite.js +1 -1
  33. package/dist/stacks/tanstack/index.cjs +205 -177
  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 +13 -10
  37. package/dist/{types-COY42xux.d.ts → types-CPkhCRxc.d.ts} +3 -3
  38. package/package.json +1 -1
@@ -46,16 +46,17 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
46
46
  function isLogLevel(value) {
47
47
  return typeof value === "string" && value in LEVEL_RANK;
48
48
  }
49
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
49
50
  function readEnvLevel() {
50
51
  try {
51
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
52
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
52
53
  const normalized = raw?.trim().toLowerCase();
53
54
  return isLogLevel(normalized) ? normalized : void 0;
54
55
  } catch {
55
56
  return void 0;
56
57
  }
57
58
  }
58
- var currentLevel = readEnvLevel() ?? "silent";
59
+ var currentLevel = readEnvLevel() ?? "debug";
59
60
  function enabled(level) {
60
61
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
61
62
  }
@@ -82,222 +83,15 @@ function describeError(err) {
82
83
  return { value: String(err) };
83
84
  }
84
85
 
85
- // src/metrics/config.ts
86
- var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
87
- var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
88
- var METRICS_SAMPLE_RATE = 1;
89
- var METRICS_FLUSH_INTERVAL_MS = 5e3;
90
- var METRICS_MAX_BATCH_SIZE = 50;
91
- function assertMetricsEndpoint(endpoint) {
92
- let url;
93
- try {
94
- url = new URL(endpoint);
95
- } catch {
96
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
97
- }
98
- if (url.protocol !== "https:" && url.protocol !== "http:") {
99
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
100
- }
101
- }
102
- function resolveMetricsConfig(config = true) {
103
- const options = typeof config === "boolean" ? { enabled: config } : config;
104
- const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
105
- assertMetricsEndpoint(endpoint);
106
- return Object.freeze({
107
- enabled: options.enabled ?? true,
108
- endpoint,
109
- headers: options.headers ?? {},
110
- apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
111
- sampleRate: METRICS_SAMPLE_RATE,
112
- flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
113
- maxBatchSize: METRICS_MAX_BATCH_SIZE
114
- });
115
- }
116
-
117
- // package.json
118
- var version = "0.16.0";
119
-
120
- // src/metrics/otlp.ts
121
- var SCOPE_NAME = "@lovable.dev/mcp-js";
122
- var EVENT_NAME = "mcp.tool.invocation";
123
- var SEVERITY_INFO = 9;
124
- function strAttr(key, value) {
125
- return { key, value: { stringValue: value } };
126
- }
127
- function intAttr(key, value) {
128
- return { key, value: { intValue: String(Math.round(value)) } };
129
- }
130
- function toLogRecord(rec) {
131
- const attributes = [
132
- strAttr("event.name", EVENT_NAME),
133
- strAttr("mcp.method", rec.method),
134
- strAttr("mcp.outcome", rec.outcome),
135
- intAttr("mcp.duration_ms", rec.durationMs)
136
- ];
137
- if (rec.tool !== null)
138
- attributes.push(strAttr("mcp.tool", rec.tool));
139
- if (rec.reqBytes !== void 0)
140
- attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
141
- if (rec.resBytes !== void 0)
142
- attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
143
- return {
144
- timeUnixNano: rec.timeUnixNano,
145
- observedTimeUnixNano: rec.timeUnixNano,
146
- severityNumber: SEVERITY_INFO,
147
- severityText: "INFO",
148
- body: { stringValue: EVENT_NAME },
149
- attributes
150
- };
151
- }
152
- function buildLogsPayload(records, server) {
153
- return JSON.stringify({
154
- resourceLogs: [
155
- {
156
- resource: {
157
- attributes: [
158
- strAttr("service.name", server.name),
159
- strAttr("service.version", server.version),
160
- strAttr("telemetry.sdk.name", SCOPE_NAME),
161
- strAttr("telemetry.sdk.version", version),
162
- strAttr("telemetry.sdk.language", "webjs")
163
- ]
164
- },
165
- scopeLogs: [
166
- {
167
- scope: { name: SCOPE_NAME, version },
168
- logRecords: records.map(toLogRecord)
169
- }
170
- ]
171
- }
172
- ]
173
- });
174
- }
175
- function nowUnixNano() {
176
- return `${Date.now()}000000`;
177
- }
178
-
179
- // src/metrics/recorder.ts
86
+ // src/metrics/impl/base.ts
180
87
  function nowMs() {
181
88
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
182
89
  }
183
- function reportInvocation(recorder, ev) {
184
- log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
185
- recorder.record(ev);
186
- }
187
- var NOOP_RECORDER = {
188
- record() {
189
- },
190
- async flush() {
191
- }
192
- };
90
+ var NOOP_RECORDER = { async emit() {
91
+ } };
193
92
  function createNoopRecorder() {
194
93
  return NOOP_RECORDER;
195
94
  }
196
- function readRuntimeEnv(name) {
197
- try {
198
- const denoEnv = globalThis.Deno?.env;
199
- const value = denoEnv?.get?.(name);
200
- if (value)
201
- return value;
202
- } catch {
203
- }
204
- try {
205
- if (typeof process !== "undefined") {
206
- const value = process.env?.[name];
207
- if (value)
208
- return value;
209
- }
210
- } catch {
211
- }
212
- return void 0;
213
- }
214
- function probeWaitUntil() {
215
- const fn = globalThis.EdgeRuntime?.waitUntil;
216
- return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
217
- }
218
- function createMetricsRecorder(ctx, deps = {}) {
219
- const { config, server } = ctx;
220
- if (!config.enabled)
221
- return NOOP_RECORDER;
222
- const doFetch = deps.fetch ?? globalThis.fetch;
223
- if (!doFetch) {
224
- log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
225
- return NOOP_RECORDER;
226
- }
227
- const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
228
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
229
- if (usesLovableEndpoint && !apiKey) {
230
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
231
- return NOOP_RECORDER;
232
- }
233
- const waitUntil = deps.waitUntil ?? probeWaitUntil();
234
- const buffer = [];
235
- let timer;
236
- const schedule = (p) => {
237
- if (waitUntil) {
238
- try {
239
- waitUntil(p);
240
- return;
241
- } catch (err) {
242
- log.warn("metrics.wait_until_failed", describeError(err));
243
- }
244
- }
245
- void p.catch(() => {
246
- });
247
- };
248
- const headers = {};
249
- if (!usesLovableEndpoint) {
250
- for (const [key, value] of Object.entries(config.headers)) {
251
- if (key.toLowerCase() !== "content-type")
252
- headers[key] = value;
253
- }
254
- }
255
- headers["content-type"] = "application/json";
256
- if (apiKey)
257
- headers.authorization = `Bearer ${apiKey}`;
258
- const flush = async () => {
259
- if (buffer.length === 0)
260
- return;
261
- const records = buffer.splice(0, buffer.length);
262
- const dropped = records.length;
263
- try {
264
- const res = await doFetch(config.endpoint, {
265
- method: "POST",
266
- headers,
267
- body: buildLogsPayload(records, server),
268
- keepalive: true
269
- });
270
- if (!res.ok) {
271
- log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
272
- }
273
- } catch (err) {
274
- log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
275
- }
276
- };
277
- const ensureTimer = () => {
278
- if (timer !== void 0)
279
- return;
280
- timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
281
- timer.unref?.();
282
- };
283
- return {
284
- record(ev) {
285
- if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
286
- return;
287
- buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
288
- ensureTimer();
289
- if (buffer.length >= config.maxBatchSize)
290
- schedule(flush());
291
- },
292
- flush
293
- };
294
- }
295
- function createRecorderForRuntime(mcp) {
296
- const config = resolveMetricsConfig(mcp.metrics);
297
- if (!config.enabled)
298
- return createNoopRecorder();
299
- return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
300
- }
301
95
 
302
96
  // src/core/promise.ts
303
97
  function cachedPromise(load, label) {
@@ -727,10 +521,10 @@ function assertRequiredScopes(auth, context) {
727
521
  throw new OAuthTokenError(403, "insufficient_scope", "Additional OAuth scope is required");
728
522
  }
729
523
  }
730
- function createRequestAuthorizer(mcp, options = {}, recorder) {
524
+ function createRequestAuthorizer(mcp, options = {}) {
731
525
  const runtime = getOAuthRuntime(mcp, options);
732
526
  return {
733
- async authorize(request) {
527
+ async authorize(request, recorder) {
734
528
  if (runtime.kind === "unconfigured")
735
529
  return { ok: true };
736
530
  const startedAt = nowMs();
@@ -746,7 +540,7 @@ function createRequestAuthorizer(mcp, options = {}, recorder) {
746
540
  } catch (err) {
747
541
  if (err instanceof OAuthConfigurationError) {
748
542
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
749
- recorder?.record({
543
+ await recorder?.emit({
750
544
  tool: null,
751
545
  method: "authorize",
752
546
  outcome: "auth_config_error",
@@ -828,11 +622,11 @@ function buildMcpListing(mcp) {
828
622
  }))
829
623
  };
830
624
  }
831
- function createListToolsHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
625
+ function createListToolsHandler(mcp, options = {}) {
832
626
  assertRestResourceBinding(mcp, options);
833
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
834
- const handle = async (request) => {
835
- const authResult = await authorizer.authorize(request);
627
+ const authorizer = createRequestAuthorizer(mcp, options);
628
+ const handle = async (request, recorder) => {
629
+ const authResult = await authorizer.authorize(request, recorder);
836
630
  if (!authResult.ok)
837
631
  return authResult.response;
838
632
  if (request.method !== "GET" && request.method !== "HEAD")
@@ -840,10 +634,10 @@ function createListToolsHandler(mcp, options = {}, recorder = createRecorderForR
840
634
  const response = Response.json(buildMcpListing(mcp));
841
635
  return request.method === "HEAD" ? headResponse(response) : response;
842
636
  };
843
- return async (request) => {
637
+ return async (request, recorder = createNoopRecorder()) => {
844
638
  if (request.method === "OPTIONS")
845
639
  return corsPreflightResponse("GET, HEAD, OPTIONS");
846
- return withCors(await handle(request));
640
+ return withCors(await handle(request, recorder));
847
641
  };
848
642
  }
849
643
 
@@ -906,11 +700,11 @@ function isEmptyArgs(value) {
906
700
  return false;
907
701
  return Object.keys(value).length === 0;
908
702
  }
909
- function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
703
+ function createInvokeToolHandler(mcp, options = {}) {
910
704
  assertRestResourceBinding(mcp, options);
911
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
912
- const handle = async (request, toolName) => {
913
- const authResult = await authorizer.authorize(request);
705
+ const authorizer = createRequestAuthorizer(mcp, options);
706
+ const handle = async (request, toolName, recorder) => {
707
+ const authResult = await authorizer.authorize(request, recorder);
914
708
  if (!authResult.ok)
915
709
  return authResult.response;
916
710
  if (request.method !== "POST")
@@ -966,7 +760,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
966
760
  try {
967
761
  result = await tool.handler(args, new ToolContext(authResult.auth));
968
762
  } catch {
969
- reportInvocation(recorder, {
763
+ await recorder.emit({
970
764
  tool: tool.name,
971
765
  method: "tools/call",
972
766
  outcome: "handler_error",
@@ -978,7 +772,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
978
772
  });
979
773
  }
980
774
  if (result == null) {
981
- reportInvocation(recorder, {
775
+ await recorder.emit({
982
776
  tool: tool.name,
983
777
  method: "tools/call",
984
778
  outcome: "handler_error",
@@ -989,7 +783,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
989
783
  headers: JSON_HEADERS
990
784
  });
991
785
  }
992
- reportInvocation(recorder, {
786
+ await recorder.emit({
993
787
  tool: tool.name,
994
788
  method: "tools/call",
995
789
  outcome: result.isError ? "tool_error" : "ok",
@@ -1001,10 +795,10 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1001
795
  isError: result.isError
1002
796
  });
1003
797
  };
1004
- return async (request, toolName) => {
798
+ return async (request, toolName, recorder = createNoopRecorder()) => {
1005
799
  if (request.method === "OPTIONS")
1006
800
  return corsPreflightResponse("POST, OPTIONS");
1007
- return withCors(await handle(request, toolName));
801
+ return withCors(await handle(request, toolName, recorder));
1008
802
  };
1009
803
  }
1010
804
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,12 +1,12 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
- import { d as McpDefinition } from '../../types-COY42xux.js';
3
- import { M as MetricsRecorder } from '../../recorder-qlzUKFxG.js';
2
+ import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
+ import { M as MetricsRecorder } from '../../base-C9rhAHZ0.js';
4
4
  import 'zod';
5
5
 
6
- type RestListToolsHandler = (request: Request) => Promise<Response>;
7
- declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestListToolsHandler;
6
+ type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
7
+ declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestListToolsHandler;
8
8
 
9
- type RestInvokeToolHandler = (request: Request, toolName: string) => Promise<Response>;
10
- declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestInvokeToolHandler;
9
+ type RestInvokeToolHandler = (request: Request, toolName: string, recorder?: MetricsRecorder) => Promise<Response>;
10
+ declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestInvokeToolHandler;
11
11
 
12
12
  export { type RestInvokeToolHandler, type RestListToolsHandler, createInvokeToolHandler, createListToolsHandler };
@@ -1,12 +1,12 @@
1
1
  import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
2
- import { d as McpDefinition } from '../../types-COY42xux.js';
3
- import { M as MetricsRecorder } from '../../recorder-qlzUKFxG.js';
2
+ import { d as McpDefinition } from '../../types-CPkhCRxc.js';
3
+ import { M as MetricsRecorder } from '../../base-C9rhAHZ0.js';
4
4
  import 'zod';
5
5
 
6
- type RestListToolsHandler = (request: Request) => Promise<Response>;
7
- declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestListToolsHandler;
6
+ type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
7
+ declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestListToolsHandler;
8
8
 
9
- type RestInvokeToolHandler = (request: Request, toolName: string) => Promise<Response>;
10
- declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions, recorder?: MetricsRecorder): RestInvokeToolHandler;
9
+ type RestInvokeToolHandler = (request: Request, toolName: string, recorder?: MetricsRecorder) => Promise<Response>;
10
+ declare function createInvokeToolHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestInvokeToolHandler;
11
11
 
12
12
  export { type RestInvokeToolHandler, type RestListToolsHandler, createInvokeToolHandler, createListToolsHandler };
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-W2EZWPJ5.js";
3
+ } from "../../chunk-57ZH2WW5.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-I5CAQUQI.js";
6
+ } from "../../chunk-OMWXY6WY.js";
7
7
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-H6BKTNJY.js";
9
- import "../../chunk-DCWYK4CA.js";
8
+ import "../../chunk-5FX6IIQ6.js";
9
+ import "../../chunk-H37EB22A.js";
10
10
  import "../../chunk-6DXGZZA4.js";
11
- import "../../chunk-SKSKC747.js";
11
+ import "../../chunk-CDZ7MBXC.js";
12
12
  export {
13
13
  createInvokeToolHandler,
14
14
  createListToolsHandler