@lovable.dev/mcp-js 0.15.1 → 0.16.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.
@@ -6,8 +6,9 @@ import {
6
6
  createRecorderForRuntime,
7
7
  createRequestAuthorizer,
8
8
  nowMs,
9
+ reportInvocation,
9
10
  withCors
10
- } from "./chunk-YTOMGJV5.js";
11
+ } from "./chunk-H6BKTNJY.js";
11
12
  import {
12
13
  describeError,
13
14
  log
@@ -24,14 +25,24 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
24
25
  try {
25
26
  result = await tool.handler(args, new ToolContext(auth));
26
27
  } catch {
27
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
28
+ reportInvocation(recorder, {
29
+ tool: tool.name,
30
+ method: "tools/call",
31
+ outcome: "handler_error",
32
+ durationMs: nowMs() - start
33
+ });
28
34
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
29
35
  }
30
36
  if (result == null) {
31
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
37
+ reportInvocation(recorder, {
38
+ tool: tool.name,
39
+ method: "tools/call",
40
+ outcome: "handler_error",
41
+ durationMs: nowMs() - start
42
+ });
32
43
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
33
44
  }
34
- recorder.record({
45
+ reportInvocation(recorder, {
35
46
  tool: tool.name,
36
47
  method: "tools/call",
37
48
  outcome: result.isError ? "tool_error" : "ok",
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-6DXGZZA4.js";
12
12
  import {
13
13
  version
14
- } from "./chunk-GIHCQT6L.js";
14
+ } from "./chunk-SKSKC747.js";
15
15
 
16
16
  // src/core/http.ts
17
17
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -112,6 +112,10 @@ function nowUnixNano() {
112
112
  function nowMs() {
113
113
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
114
114
  }
115
+ function reportInvocation(recorder, ev) {
116
+ log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
117
+ recorder.record(ev);
118
+ }
115
119
  var NOOP_RECORDER = {
116
120
  record() {
117
121
  },
@@ -148,12 +152,14 @@ function createMetricsRecorder(ctx, deps = {}) {
148
152
  if (!config.enabled)
149
153
  return NOOP_RECORDER;
150
154
  const doFetch = deps.fetch ?? globalThis.fetch;
151
- if (!doFetch)
155
+ if (!doFetch) {
156
+ log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
152
157
  return NOOP_RECORDER;
158
+ }
153
159
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
154
160
  const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
155
161
  if (usesLovableEndpoint && !apiKey) {
156
- log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
162
+ log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
157
163
  return NOOP_RECORDER;
158
164
  }
159
165
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
@@ -164,7 +170,8 @@ function createMetricsRecorder(ctx, deps = {}) {
164
170
  try {
165
171
  waitUntil(p);
166
172
  return;
167
- } catch {
173
+ } catch (err) {
174
+ log.warn("metrics.wait_until_failed", describeError(err));
168
175
  }
169
176
  }
170
177
  void p.catch(() => {
@@ -184,6 +191,7 @@ function createMetricsRecorder(ctx, deps = {}) {
184
191
  if (buffer.length === 0)
185
192
  return;
186
193
  const records = buffer.splice(0, buffer.length);
194
+ const dropped = records.length;
187
195
  try {
188
196
  const res = await doFetch(config.endpoint, {
189
197
  method: "POST",
@@ -191,10 +199,11 @@ function createMetricsRecorder(ctx, deps = {}) {
191
199
  body: buildLogsPayload(records, server),
192
200
  keepalive: true
193
201
  });
194
- if (!res.ok)
195
- log.debug("metrics.flush_rejected", { status: res.status });
202
+ if (!res.ok) {
203
+ log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
204
+ }
196
205
  } catch (err) {
197
- log.debug("metrics.flush_failed", describeError(err));
206
+ log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
198
207
  }
199
208
  };
200
209
  const ensureTimer = () => {
@@ -670,6 +679,7 @@ export {
670
679
  headResponse,
671
680
  methodNotAllowed,
672
681
  nowMs,
682
+ reportInvocation,
673
683
  createRecorderForRuntime,
674
684
  resolveProtectedResource,
675
685
  assertResourcePathShape,
@@ -6,7 +6,7 @@ import {
6
6
  headResponse,
7
7
  methodNotAllowed,
8
8
  withCors
9
- } from "./chunk-YTOMGJV5.js";
9
+ } from "./chunk-H6BKTNJY.js";
10
10
 
11
11
  // src/protocols/rest/list-tools.ts
12
12
  import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.15.1";
2
+ var version = "0.16.0";
3
3
 
4
4
  export {
5
5
  version
@@ -7,7 +7,7 @@ import {
7
7
  oauthConfigurationErrorResponse,
8
8
  resolveProtectedResource,
9
9
  withCors
10
- } from "./chunk-YTOMGJV5.js";
10
+ } from "./chunk-H6BKTNJY.js";
11
11
  import {
12
12
  describeError,
13
13
  log
@@ -9,8 +9,9 @@ import {
9
9
  createRequestAuthorizer,
10
10
  methodNotAllowed,
11
11
  nowMs,
12
+ reportInvocation,
12
13
  withCors
13
- } from "./chunk-YTOMGJV5.js";
14
+ } from "./chunk-H6BKTNJY.js";
14
15
 
15
16
  // src/protocols/rest/invoke-tool.ts
16
17
  import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -86,20 +87,30 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
86
87
  try {
87
88
  result = await tool.handler(args, new ToolContext(authResult.auth));
88
89
  } catch {
89
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
90
+ reportInvocation(recorder, {
91
+ tool: tool.name,
92
+ method: "tools/call",
93
+ outcome: "handler_error",
94
+ durationMs: nowMs() - start
95
+ });
90
96
  return new Response(JSON.stringify({ error: "handler threw", tool: toolName }), {
91
97
  status: 500,
92
98
  headers: JSON_HEADERS
93
99
  });
94
100
  }
95
101
  if (result == null) {
96
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
102
+ reportInvocation(recorder, {
103
+ tool: tool.name,
104
+ method: "tools/call",
105
+ outcome: "handler_error",
106
+ durationMs: nowMs() - start
107
+ });
97
108
  return new Response(JSON.stringify({ error: `tool "${toolName}" returned no result` }), {
98
109
  status: 500,
99
110
  headers: JSON_HEADERS
100
111
  });
101
112
  }
102
- recorder.record({
113
+ reportInvocation(recorder, {
103
114
  tool: tool.name,
104
115
  method: "tools/call",
105
116
  outcome: result.isError ? "tool_error" : "ok",
@@ -13,7 +13,7 @@ function isFileMissing(err) {
13
13
  }
14
14
 
15
15
  // package.json
16
- var version = "0.15.1";
16
+ var version = "0.16.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,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildMcpListing
4
- } from "../chunk-QT5L4CS3.js";
5
- import "../chunk-YTOMGJV5.js";
4
+ } from "../chunk-I5CAQUQI.js";
5
+ import "../chunk-H6BKTNJY.js";
6
6
  import "../chunk-DCWYK4CA.js";
7
7
  import "../chunk-6DXGZZA4.js";
8
8
  import {
@@ -10,7 +10,7 @@ import {
10
10
  } from "../chunk-Y3ZFPEQH.js";
11
11
  import {
12
12
  version
13
- } from "../chunk-GIHCQT6L.js";
13
+ } from "../chunk-SKSKC747.js";
14
14
 
15
15
  // src/manifest/io.ts
16
16
  import { randomUUID } from "crypto";
@@ -105,7 +105,7 @@ function resolveMetricsConfig(config = true) {
105
105
  }
106
106
 
107
107
  // package.json
108
- var version = "0.15.1";
108
+ var version = "0.16.0";
109
109
 
110
110
  // src/metrics/otlp.ts
111
111
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -170,6 +170,10 @@ function nowUnixNano() {
170
170
  function nowMs() {
171
171
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
172
172
  }
173
+ function reportInvocation(recorder, ev) {
174
+ log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
175
+ recorder.record(ev);
176
+ }
173
177
  var NOOP_RECORDER = {
174
178
  record() {
175
179
  },
@@ -206,12 +210,14 @@ function createMetricsRecorder(ctx, deps = {}) {
206
210
  if (!config.enabled)
207
211
  return NOOP_RECORDER;
208
212
  const doFetch = deps.fetch ?? globalThis.fetch;
209
- if (!doFetch)
213
+ if (!doFetch) {
214
+ log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
210
215
  return NOOP_RECORDER;
216
+ }
211
217
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
212
218
  const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
213
219
  if (usesLovableEndpoint && !apiKey) {
214
- log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
220
+ log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
215
221
  return NOOP_RECORDER;
216
222
  }
217
223
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
@@ -222,7 +228,8 @@ function createMetricsRecorder(ctx, deps = {}) {
222
228
  try {
223
229
  waitUntil(p);
224
230
  return;
225
- } catch {
231
+ } catch (err) {
232
+ log.warn("metrics.wait_until_failed", describeError(err));
226
233
  }
227
234
  }
228
235
  void p.catch(() => {
@@ -242,6 +249,7 @@ function createMetricsRecorder(ctx, deps = {}) {
242
249
  if (buffer.length === 0)
243
250
  return;
244
251
  const records = buffer.splice(0, buffer.length);
252
+ const dropped = records.length;
245
253
  try {
246
254
  const res = await doFetch(config.endpoint, {
247
255
  method: "POST",
@@ -249,10 +257,11 @@ function createMetricsRecorder(ctx, deps = {}) {
249
257
  body: buildLogsPayload(records, server),
250
258
  keepalive: true
251
259
  });
252
- if (!res.ok)
253
- log.debug("metrics.flush_rejected", { status: res.status });
260
+ if (!res.ok) {
261
+ log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
262
+ }
254
263
  } catch (err) {
255
- log.debug("metrics.flush_failed", describeError(err));
264
+ log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
256
265
  }
257
266
  };
258
267
  const ensureTimer = () => {
@@ -830,14 +839,24 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
830
839
  try {
831
840
  result = await tool.handler(args, new ToolContext(auth));
832
841
  } catch {
833
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
842
+ reportInvocation(recorder, {
843
+ tool: tool.name,
844
+ method: "tools/call",
845
+ outcome: "handler_error",
846
+ durationMs: nowMs() - start
847
+ });
834
848
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
835
849
  }
836
850
  if (result == null) {
837
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
851
+ reportInvocation(recorder, {
852
+ tool: tool.name,
853
+ method: "tools/call",
854
+ outcome: "handler_error",
855
+ durationMs: nowMs() - start
856
+ });
838
857
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
839
858
  }
840
- recorder.record({
859
+ reportInvocation(recorder, {
841
860
  tool: tool.name,
842
861
  method: "tools/call",
843
862
  outcome: result.isError ? "tool_error" : "ok",
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-UCPYLSNN.js";
3
+ } from "../../chunk-EZQVUNXB.js";
4
4
  import "../../chunk-MA5H6PSF.js";
5
- import "../../chunk-YTOMGJV5.js";
5
+ import "../../chunk-H6BKTNJY.js";
6
6
  import "../../chunk-DCWYK4CA.js";
7
7
  import "../../chunk-6DXGZZA4.js";
8
- import "../../chunk-GIHCQT6L.js";
8
+ import "../../chunk-SKSKC747.js";
9
9
  export {
10
10
  createMcpProtocolHandler
11
11
  };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createOAuthProtectedResourceMetadataHandler
3
- } from "../chunk-ILYTJXDR.js";
4
- import "../chunk-YTOMGJV5.js";
3
+ } from "../chunk-T24Z753F.js";
4
+ import "../chunk-H6BKTNJY.js";
5
5
  import "../chunk-DCWYK4CA.js";
6
6
  import "../chunk-6DXGZZA4.js";
7
- import "../chunk-GIHCQT6L.js";
7
+ import "../chunk-SKSKC747.js";
8
8
  export {
9
9
  createOAuthProtectedResourceMetadataHandler
10
10
  };
@@ -115,7 +115,7 @@ function resolveMetricsConfig(config = true) {
115
115
  }
116
116
 
117
117
  // package.json
118
- var version = "0.15.1";
118
+ var version = "0.16.0";
119
119
 
120
120
  // src/metrics/otlp.ts
121
121
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -180,6 +180,10 @@ function nowUnixNano() {
180
180
  function nowMs() {
181
181
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
182
182
  }
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
+ }
183
187
  var NOOP_RECORDER = {
184
188
  record() {
185
189
  },
@@ -216,12 +220,14 @@ function createMetricsRecorder(ctx, deps = {}) {
216
220
  if (!config.enabled)
217
221
  return NOOP_RECORDER;
218
222
  const doFetch = deps.fetch ?? globalThis.fetch;
219
- if (!doFetch)
223
+ if (!doFetch) {
224
+ log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
220
225
  return NOOP_RECORDER;
226
+ }
221
227
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
222
228
  const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
223
229
  if (usesLovableEndpoint && !apiKey) {
224
- log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
230
+ log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
225
231
  return NOOP_RECORDER;
226
232
  }
227
233
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
@@ -232,7 +238,8 @@ function createMetricsRecorder(ctx, deps = {}) {
232
238
  try {
233
239
  waitUntil(p);
234
240
  return;
235
- } catch {
241
+ } catch (err) {
242
+ log.warn("metrics.wait_until_failed", describeError(err));
236
243
  }
237
244
  }
238
245
  void p.catch(() => {
@@ -252,6 +259,7 @@ function createMetricsRecorder(ctx, deps = {}) {
252
259
  if (buffer.length === 0)
253
260
  return;
254
261
  const records = buffer.splice(0, buffer.length);
262
+ const dropped = records.length;
255
263
  try {
256
264
  const res = await doFetch(config.endpoint, {
257
265
  method: "POST",
@@ -259,10 +267,11 @@ function createMetricsRecorder(ctx, deps = {}) {
259
267
  body: buildLogsPayload(records, server),
260
268
  keepalive: true
261
269
  });
262
- if (!res.ok)
263
- log.debug("metrics.flush_rejected", { status: res.status });
270
+ if (!res.ok) {
271
+ log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
272
+ }
264
273
  } catch (err) {
265
- log.debug("metrics.flush_failed", describeError(err));
274
+ log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
266
275
  }
267
276
  };
268
277
  const ensureTimer = () => {
@@ -957,20 +966,30 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
957
966
  try {
958
967
  result = await tool.handler(args, new ToolContext(authResult.auth));
959
968
  } catch {
960
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
969
+ reportInvocation(recorder, {
970
+ tool: tool.name,
971
+ method: "tools/call",
972
+ outcome: "handler_error",
973
+ durationMs: nowMs() - start
974
+ });
961
975
  return new Response(JSON.stringify({ error: "handler threw", tool: toolName }), {
962
976
  status: 500,
963
977
  headers: JSON_HEADERS
964
978
  });
965
979
  }
966
980
  if (result == null) {
967
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
981
+ reportInvocation(recorder, {
982
+ tool: tool.name,
983
+ method: "tools/call",
984
+ outcome: "handler_error",
985
+ durationMs: nowMs() - start
986
+ });
968
987
  return new Response(JSON.stringify({ error: `tool "${toolName}" returned no result` }), {
969
988
  status: 500,
970
989
  headers: JSON_HEADERS
971
990
  });
972
991
  }
973
- recorder.record({
992
+ reportInvocation(recorder, {
974
993
  tool: tool.name,
975
994
  method: "tools/call",
976
995
  outcome: result.isError ? "tool_error" : "ok",
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-CEDD57G2.js";
3
+ } from "../../chunk-W2EZWPJ5.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-QT5L4CS3.js";
6
+ } from "../../chunk-I5CAQUQI.js";
7
7
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-YTOMGJV5.js";
8
+ import "../../chunk-H6BKTNJY.js";
9
9
  import "../../chunk-DCWYK4CA.js";
10
10
  import "../../chunk-6DXGZZA4.js";
11
- import "../../chunk-GIHCQT6L.js";
11
+ import "../../chunk-SKSKC747.js";
12
12
  export {
13
13
  createInvokeToolHandler,
14
14
  createListToolsHandler
@@ -169,7 +169,7 @@ function resolveMetricsConfig(config = true) {
169
169
  }
170
170
 
171
171
  // package.json
172
- var version = "0.15.1";
172
+ var version = "0.16.0";
173
173
 
174
174
  // src/metrics/otlp.ts
175
175
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -234,6 +234,10 @@ function nowUnixNano() {
234
234
  function nowMs() {
235
235
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
236
236
  }
237
+ function reportInvocation(recorder, ev) {
238
+ log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
239
+ recorder.record(ev);
240
+ }
237
241
  var NOOP_RECORDER = {
238
242
  record() {
239
243
  },
@@ -270,12 +274,14 @@ function createMetricsRecorder(ctx, deps = {}) {
270
274
  if (!config.enabled)
271
275
  return NOOP_RECORDER;
272
276
  const doFetch = deps.fetch ?? globalThis.fetch;
273
- if (!doFetch)
277
+ if (!doFetch) {
278
+ log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
274
279
  return NOOP_RECORDER;
280
+ }
275
281
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
276
282
  const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
277
283
  if (usesLovableEndpoint && !apiKey) {
278
- log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
284
+ log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
279
285
  return NOOP_RECORDER;
280
286
  }
281
287
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
@@ -286,7 +292,8 @@ function createMetricsRecorder(ctx, deps = {}) {
286
292
  try {
287
293
  waitUntil(p);
288
294
  return;
289
- } catch {
295
+ } catch (err) {
296
+ log.warn("metrics.wait_until_failed", describeError(err));
290
297
  }
291
298
  }
292
299
  void p.catch(() => {
@@ -306,6 +313,7 @@ function createMetricsRecorder(ctx, deps = {}) {
306
313
  if (buffer.length === 0)
307
314
  return;
308
315
  const records = buffer.splice(0, buffer.length);
316
+ const dropped = records.length;
309
317
  try {
310
318
  const res = await doFetch(config.endpoint, {
311
319
  method: "POST",
@@ -313,10 +321,11 @@ function createMetricsRecorder(ctx, deps = {}) {
313
321
  body: buildLogsPayload(records, server),
314
322
  keepalive: true
315
323
  });
316
- if (!res.ok)
317
- log.debug("metrics.flush_rejected", { status: res.status });
324
+ if (!res.ok) {
325
+ log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
326
+ }
318
327
  } catch (err) {
319
- log.debug("metrics.flush_failed", describeError(err));
328
+ log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
320
329
  }
321
330
  };
322
331
  const ensureTimer = () => {
@@ -870,14 +879,24 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
870
879
  try {
871
880
  result = await tool.handler(args, new ToolContext(auth));
872
881
  } catch {
873
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
882
+ reportInvocation(recorder, {
883
+ tool: tool.name,
884
+ method: "tools/call",
885
+ outcome: "handler_error",
886
+ durationMs: nowMs() - start
887
+ });
874
888
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
875
889
  }
876
890
  if (result == null) {
877
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
891
+ reportInvocation(recorder, {
892
+ tool: tool.name,
893
+ method: "tools/call",
894
+ outcome: "handler_error",
895
+ durationMs: nowMs() - start
896
+ });
878
897
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
879
898
  }
880
- recorder.record({
899
+ reportInvocation(recorder, {
881
900
  tool: tool.name,
882
901
  method: "tools/call",
883
902
  outcome: result.isError ? "tool_error" : "ok",
@@ -1110,20 +1129,30 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1110
1129
  try {
1111
1130
  result = await tool.handler(args, new ToolContext(authResult.auth));
1112
1131
  } catch {
1113
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
1132
+ reportInvocation(recorder, {
1133
+ tool: tool.name,
1134
+ method: "tools/call",
1135
+ outcome: "handler_error",
1136
+ durationMs: nowMs() - start
1137
+ });
1114
1138
  return new Response(JSON.stringify({ error: "handler threw", tool: toolName }), {
1115
1139
  status: 500,
1116
1140
  headers: JSON_HEADERS
1117
1141
  });
1118
1142
  }
1119
1143
  if (result == null) {
1120
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
1144
+ reportInvocation(recorder, {
1145
+ tool: tool.name,
1146
+ method: "tools/call",
1147
+ outcome: "handler_error",
1148
+ durationMs: nowMs() - start
1149
+ });
1121
1150
  return new Response(JSON.stringify({ error: `tool "${toolName}" returned no result` }), {
1122
1151
  status: 500,
1123
1152
  headers: JSON_HEADERS
1124
1153
  });
1125
1154
  }
1126
- recorder.record({
1155
+ reportInvocation(recorder, {
1127
1156
  tool: tool.name,
1128
1157
  method: "tools/call",
1129
1158
  outcome: result.isError ? "tool_error" : "ok",
@@ -3,21 +3,21 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-UCPYLSNN.js";
6
+ } from "../../chunk-EZQVUNXB.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-ILYTJXDR.js";
9
+ } from "../../chunk-T24Z753F.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-CEDD57G2.js";
12
+ } from "../../chunk-W2EZWPJ5.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-QT5L4CS3.js";
15
+ } from "../../chunk-I5CAQUQI.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
17
  import {
18
18
  assertResourcePathShape,
19
19
  createRecorderForRuntime
20
- } from "../../chunk-YTOMGJV5.js";
20
+ } from "../../chunk-H6BKTNJY.js";
21
21
  import {
22
22
  trimTrailingSlash
23
23
  } from "../../chunk-DCWYK4CA.js";
@@ -28,7 +28,7 @@ import {
28
28
  FUNCTIONS_MOUNT_PREFIX,
29
29
  assertFunctionName
30
30
  } from "../../chunk-XQWJN6DC.js";
31
- import "../../chunk-GIHCQT6L.js";
31
+ import "../../chunk-SKSKC747.js";
32
32
 
33
33
  // src/stacks/supabase/handler.ts
34
34
  function deriveResourcePath(options) {
@@ -33,7 +33,7 @@ var import_node_fs = require("fs");
33
33
  var import_node_path = require("path");
34
34
 
35
35
  // package.json
36
- var version = "0.15.1";
36
+ var version = "0.16.0";
37
37
 
38
38
  // src/core/fs-errors.ts
39
39
  function isFileMissing(err) {
@@ -7,7 +7,7 @@ import {
7
7
  } from "../../chunk-XQWJN6DC.js";
8
8
  import {
9
9
  version
10
- } from "../../chunk-GIHCQT6L.js";
10
+ } from "../../chunk-SKSKC747.js";
11
11
 
12
12
  // src/stacks/supabase/vite.ts
13
13
  import { resolve as resolve2, sep as sep2 } from "path";
@@ -140,7 +140,7 @@ function resolveMetricsConfig(config = true) {
140
140
  }
141
141
 
142
142
  // package.json
143
- var version = "0.15.1";
143
+ var version = "0.16.0";
144
144
 
145
145
  // src/metrics/otlp.ts
146
146
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -205,6 +205,10 @@ function nowUnixNano() {
205
205
  function nowMs() {
206
206
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
207
207
  }
208
+ function reportInvocation(recorder, ev) {
209
+ log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
210
+ recorder.record(ev);
211
+ }
208
212
  var NOOP_RECORDER = {
209
213
  record() {
210
214
  },
@@ -241,12 +245,14 @@ function createMetricsRecorder(ctx, deps = {}) {
241
245
  if (!config.enabled)
242
246
  return NOOP_RECORDER;
243
247
  const doFetch = deps.fetch ?? globalThis.fetch;
244
- if (!doFetch)
248
+ if (!doFetch) {
249
+ log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
245
250
  return NOOP_RECORDER;
251
+ }
246
252
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
247
253
  const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
248
254
  if (usesLovableEndpoint && !apiKey) {
249
- log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
255
+ log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
250
256
  return NOOP_RECORDER;
251
257
  }
252
258
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
@@ -257,7 +263,8 @@ function createMetricsRecorder(ctx, deps = {}) {
257
263
  try {
258
264
  waitUntil(p);
259
265
  return;
260
- } catch {
266
+ } catch (err) {
267
+ log.warn("metrics.wait_until_failed", describeError(err));
261
268
  }
262
269
  }
263
270
  void p.catch(() => {
@@ -277,6 +284,7 @@ function createMetricsRecorder(ctx, deps = {}) {
277
284
  if (buffer.length === 0)
278
285
  return;
279
286
  const records = buffer.splice(0, buffer.length);
287
+ const dropped = records.length;
280
288
  try {
281
289
  const res = await doFetch(config.endpoint, {
282
290
  method: "POST",
@@ -284,10 +292,11 @@ function createMetricsRecorder(ctx, deps = {}) {
284
292
  body: buildLogsPayload(records, server),
285
293
  keepalive: true
286
294
  });
287
- if (!res.ok)
288
- log.debug("metrics.flush_rejected", { status: res.status });
295
+ if (!res.ok) {
296
+ log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
297
+ }
289
298
  } catch (err) {
290
- log.debug("metrics.flush_failed", describeError(err));
299
+ log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
291
300
  }
292
301
  };
293
302
  const ensureTimer = () => {
@@ -873,14 +882,24 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
873
882
  try {
874
883
  result = await tool.handler(args, new ToolContext(auth));
875
884
  } catch {
876
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
885
+ reportInvocation(recorder, {
886
+ tool: tool.name,
887
+ method: "tools/call",
888
+ outcome: "handler_error",
889
+ durationMs: nowMs() - start
890
+ });
877
891
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
878
892
  }
879
893
  if (result == null) {
880
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
894
+ reportInvocation(recorder, {
895
+ tool: tool.name,
896
+ method: "tools/call",
897
+ outcome: "handler_error",
898
+ durationMs: nowMs() - start
899
+ });
881
900
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
882
901
  }
883
- recorder.record({
902
+ reportInvocation(recorder, {
884
903
  tool: tool.name,
885
904
  method: "tools/call",
886
905
  outcome: result.isError ? "tool_error" : "ok",
@@ -1113,20 +1132,30 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1113
1132
  try {
1114
1133
  result = await tool.handler(args, new ToolContext(authResult.auth));
1115
1134
  } catch {
1116
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
1135
+ reportInvocation(recorder, {
1136
+ tool: tool.name,
1137
+ method: "tools/call",
1138
+ outcome: "handler_error",
1139
+ durationMs: nowMs() - start
1140
+ });
1117
1141
  return new Response(JSON.stringify({ error: "handler threw", tool: toolName }), {
1118
1142
  status: 500,
1119
1143
  headers: JSON_HEADERS
1120
1144
  });
1121
1145
  }
1122
1146
  if (result == null) {
1123
- recorder.record({ tool: tool.name, method: "tools/call", outcome: "handler_error", durationMs: nowMs() - start });
1147
+ reportInvocation(recorder, {
1148
+ tool: tool.name,
1149
+ method: "tools/call",
1150
+ outcome: "handler_error",
1151
+ durationMs: nowMs() - start
1152
+ });
1124
1153
  return new Response(JSON.stringify({ error: `tool "${toolName}" returned no result` }), {
1125
1154
  status: 500,
1126
1155
  headers: JSON_HEADERS
1127
1156
  });
1128
1157
  }
1129
- recorder.record({
1158
+ reportInvocation(recorder, {
1130
1159
  tool: tool.name,
1131
1160
  method: "tools/call",
1132
1161
  outcome: result.isError ? "tool_error" : "ok",
@@ -3,21 +3,21 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-UCPYLSNN.js";
6
+ } from "../../chunk-EZQVUNXB.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-ILYTJXDR.js";
9
+ } from "../../chunk-T24Z753F.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-CEDD57G2.js";
12
+ } from "../../chunk-W2EZWPJ5.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-QT5L4CS3.js";
15
+ } from "../../chunk-I5CAQUQI.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
- import "../../chunk-YTOMGJV5.js";
17
+ import "../../chunk-H6BKTNJY.js";
18
18
  import "../../chunk-DCWYK4CA.js";
19
19
  import "../../chunk-6DXGZZA4.js";
20
- import "../../chunk-GIHCQT6L.js";
20
+ import "../../chunk-SKSKC747.js";
21
21
 
22
22
  // src/stacks/tanstack/handlers.ts
23
23
  function forwarded(request, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/mcp-js",
3
- "version": "0.15.1",
3
+ "version": "0.16.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": {