@lovable.dev/mcp-js 0.15.0 → 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.
- package/dist/{chunk-QC3DXQTH.js → chunk-DCWYK4CA.js} +34 -0
- package/dist/{chunk-RHDEW56Y.js → chunk-EZQVUNXB.js} +20 -11
- package/dist/{chunk-G4XA7IJM.js → chunk-H6BKTNJY.js} +199 -2
- package/dist/{chunk-VNRQPA4K.js → chunk-I5CAQUQI.js} +4 -3
- package/dist/{chunk-P3F324UC.js → chunk-MA5H6PSF.js} +0 -34
- package/dist/{chunk-LWHVXXKQ.js → chunk-SKSKC747.js} +1 -1
- package/dist/{chunk-QDKOF4UF.js → chunk-T24Z753F.js} +2 -2
- package/dist/{chunk-T2RED2TG.js → chunk-W2EZWPJ5.js} +19 -10
- package/dist/cli/extract-manifest.cjs +1 -1
- package/dist/cli/extract-manifest.js +4 -4
- package/dist/index.js +4 -4
- package/dist/protocols/mcp/index.cjs +239 -213
- package/dist/protocols/mcp/index.d.cts +1 -1
- package/dist/protocols/mcp/index.d.ts +1 -1
- package/dist/protocols/mcp/index.js +5 -6
- package/dist/protocols/oauth-metadata.js +4 -3
- package/dist/protocols/rest/index.cjs +241 -215
- package/dist/protocols/rest/index.d.cts +2 -2
- package/dist/protocols/rest/index.d.ts +2 -2
- package/dist/protocols/rest/index.js +6 -7
- package/dist/{recorder-B-eJU4Qu.d.ts → recorder-qlzUKFxG.d.ts} +3 -3
- package/dist/stacks/supabase/index.cjs +55 -19
- package/dist/stacks/supabase/index.js +10 -12
- package/dist/stacks/supabase/vite.cjs +28 -4
- package/dist/stacks/supabase/vite.js +28 -4
- package/dist/stacks/tanstack/index.cjs +255 -219
- package/dist/stacks/tanstack/index.js +8 -9
- package/package.json +1 -1
- package/dist/chunk-XQSTN54Y.js +0 -189
|
@@ -72,6 +72,223 @@ function describeError(err) {
|
|
|
72
72
|
return { value: String(err) };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
// src/metrics/config.ts
|
|
76
|
+
var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
|
|
77
|
+
var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
|
|
78
|
+
var METRICS_SAMPLE_RATE = 1;
|
|
79
|
+
var METRICS_FLUSH_INTERVAL_MS = 5e3;
|
|
80
|
+
var METRICS_MAX_BATCH_SIZE = 50;
|
|
81
|
+
function assertMetricsEndpoint(endpoint) {
|
|
82
|
+
let url;
|
|
83
|
+
try {
|
|
84
|
+
url = new URL(endpoint);
|
|
85
|
+
} catch {
|
|
86
|
+
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
|
|
87
|
+
}
|
|
88
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
89
|
+
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function resolveMetricsConfig(config = true) {
|
|
93
|
+
const options = typeof config === "boolean" ? { enabled: config } : config;
|
|
94
|
+
const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
|
|
95
|
+
assertMetricsEndpoint(endpoint);
|
|
96
|
+
return Object.freeze({
|
|
97
|
+
enabled: options.enabled ?? true,
|
|
98
|
+
endpoint,
|
|
99
|
+
headers: options.headers ?? {},
|
|
100
|
+
apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
|
|
101
|
+
sampleRate: METRICS_SAMPLE_RATE,
|
|
102
|
+
flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
|
|
103
|
+
maxBatchSize: METRICS_MAX_BATCH_SIZE
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// package.json
|
|
108
|
+
var version = "0.16.0";
|
|
109
|
+
|
|
110
|
+
// src/metrics/otlp.ts
|
|
111
|
+
var SCOPE_NAME = "@lovable.dev/mcp-js";
|
|
112
|
+
var EVENT_NAME = "mcp.tool.invocation";
|
|
113
|
+
var SEVERITY_INFO = 9;
|
|
114
|
+
function strAttr(key, value) {
|
|
115
|
+
return { key, value: { stringValue: value } };
|
|
116
|
+
}
|
|
117
|
+
function intAttr(key, value) {
|
|
118
|
+
return { key, value: { intValue: String(Math.round(value)) } };
|
|
119
|
+
}
|
|
120
|
+
function toLogRecord(rec) {
|
|
121
|
+
const attributes = [
|
|
122
|
+
strAttr("event.name", EVENT_NAME),
|
|
123
|
+
strAttr("mcp.method", rec.method),
|
|
124
|
+
strAttr("mcp.outcome", rec.outcome),
|
|
125
|
+
intAttr("mcp.duration_ms", rec.durationMs)
|
|
126
|
+
];
|
|
127
|
+
if (rec.tool !== null)
|
|
128
|
+
attributes.push(strAttr("mcp.tool", rec.tool));
|
|
129
|
+
if (rec.reqBytes !== void 0)
|
|
130
|
+
attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
|
|
131
|
+
if (rec.resBytes !== void 0)
|
|
132
|
+
attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
|
|
133
|
+
return {
|
|
134
|
+
timeUnixNano: rec.timeUnixNano,
|
|
135
|
+
observedTimeUnixNano: rec.timeUnixNano,
|
|
136
|
+
severityNumber: SEVERITY_INFO,
|
|
137
|
+
severityText: "INFO",
|
|
138
|
+
body: { stringValue: EVENT_NAME },
|
|
139
|
+
attributes
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function buildLogsPayload(records, server) {
|
|
143
|
+
return JSON.stringify({
|
|
144
|
+
resourceLogs: [
|
|
145
|
+
{
|
|
146
|
+
resource: {
|
|
147
|
+
attributes: [
|
|
148
|
+
strAttr("service.name", server.name),
|
|
149
|
+
strAttr("service.version", server.version),
|
|
150
|
+
strAttr("telemetry.sdk.name", SCOPE_NAME),
|
|
151
|
+
strAttr("telemetry.sdk.version", version),
|
|
152
|
+
strAttr("telemetry.sdk.language", "webjs")
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
scopeLogs: [
|
|
156
|
+
{
|
|
157
|
+
scope: { name: SCOPE_NAME, version },
|
|
158
|
+
logRecords: records.map(toLogRecord)
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function nowUnixNano() {
|
|
166
|
+
return `${Date.now()}000000`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/metrics/recorder.ts
|
|
170
|
+
function nowMs() {
|
|
171
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
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
|
+
}
|
|
177
|
+
var NOOP_RECORDER = {
|
|
178
|
+
record() {
|
|
179
|
+
},
|
|
180
|
+
async flush() {
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
function createNoopRecorder() {
|
|
184
|
+
return NOOP_RECORDER;
|
|
185
|
+
}
|
|
186
|
+
function readRuntimeEnv(name) {
|
|
187
|
+
try {
|
|
188
|
+
const denoEnv = globalThis.Deno?.env;
|
|
189
|
+
const value = denoEnv?.get?.(name);
|
|
190
|
+
if (value)
|
|
191
|
+
return value;
|
|
192
|
+
} catch {
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
if (typeof process !== "undefined") {
|
|
196
|
+
const value = process.env?.[name];
|
|
197
|
+
if (value)
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
}
|
|
202
|
+
return void 0;
|
|
203
|
+
}
|
|
204
|
+
function probeWaitUntil() {
|
|
205
|
+
const fn = globalThis.EdgeRuntime?.waitUntil;
|
|
206
|
+
return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
|
|
207
|
+
}
|
|
208
|
+
function createMetricsRecorder(ctx, deps = {}) {
|
|
209
|
+
const { config, server } = ctx;
|
|
210
|
+
if (!config.enabled)
|
|
211
|
+
return NOOP_RECORDER;
|
|
212
|
+
const doFetch = deps.fetch ?? globalThis.fetch;
|
|
213
|
+
if (!doFetch) {
|
|
214
|
+
log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
|
|
215
|
+
return NOOP_RECORDER;
|
|
216
|
+
}
|
|
217
|
+
const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
|
|
218
|
+
const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
|
|
219
|
+
if (usesLovableEndpoint && !apiKey) {
|
|
220
|
+
log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
|
|
221
|
+
return NOOP_RECORDER;
|
|
222
|
+
}
|
|
223
|
+
const waitUntil = deps.waitUntil ?? probeWaitUntil();
|
|
224
|
+
const buffer = [];
|
|
225
|
+
let timer;
|
|
226
|
+
const schedule = (p) => {
|
|
227
|
+
if (waitUntil) {
|
|
228
|
+
try {
|
|
229
|
+
waitUntil(p);
|
|
230
|
+
return;
|
|
231
|
+
} catch (err) {
|
|
232
|
+
log.warn("metrics.wait_until_failed", describeError(err));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
void p.catch(() => {
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
const headers = {};
|
|
239
|
+
if (!usesLovableEndpoint) {
|
|
240
|
+
for (const [key, value] of Object.entries(config.headers)) {
|
|
241
|
+
if (key.toLowerCase() !== "content-type")
|
|
242
|
+
headers[key] = value;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
headers["content-type"] = "application/json";
|
|
246
|
+
if (apiKey)
|
|
247
|
+
headers.authorization = `Bearer ${apiKey}`;
|
|
248
|
+
const flush = async () => {
|
|
249
|
+
if (buffer.length === 0)
|
|
250
|
+
return;
|
|
251
|
+
const records = buffer.splice(0, buffer.length);
|
|
252
|
+
const dropped = records.length;
|
|
253
|
+
try {
|
|
254
|
+
const res = await doFetch(config.endpoint, {
|
|
255
|
+
method: "POST",
|
|
256
|
+
headers,
|
|
257
|
+
body: buildLogsPayload(records, server),
|
|
258
|
+
keepalive: true
|
|
259
|
+
});
|
|
260
|
+
if (!res.ok) {
|
|
261
|
+
log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const ensureTimer = () => {
|
|
268
|
+
if (timer !== void 0)
|
|
269
|
+
return;
|
|
270
|
+
timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
|
|
271
|
+
timer.unref?.();
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
record(ev) {
|
|
275
|
+
if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
|
|
276
|
+
return;
|
|
277
|
+
buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
|
|
278
|
+
ensureTimer();
|
|
279
|
+
if (buffer.length >= config.maxBatchSize)
|
|
280
|
+
schedule(flush());
|
|
281
|
+
},
|
|
282
|
+
flush
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function createRecorderForRuntime(mcp) {
|
|
286
|
+
const config = resolveMetricsConfig(mcp.metrics);
|
|
287
|
+
if (!config.enabled)
|
|
288
|
+
return createNoopRecorder();
|
|
289
|
+
return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
|
|
290
|
+
}
|
|
291
|
+
|
|
75
292
|
// src/core/promise.ts
|
|
76
293
|
function cachedPromise(load, label) {
|
|
77
294
|
let settled = false;
|
|
@@ -492,12 +709,13 @@ function assertRequiredScopes(auth, context) {
|
|
|
492
709
|
throw new OAuthTokenError(403, "insufficient_scope", "Additional OAuth scope is required");
|
|
493
710
|
}
|
|
494
711
|
}
|
|
495
|
-
function createRequestAuthorizer(mcp, options = {}) {
|
|
712
|
+
function createRequestAuthorizer(mcp, options = {}, recorder) {
|
|
496
713
|
const runtime = getOAuthRuntime(mcp, options);
|
|
497
714
|
return {
|
|
498
715
|
async authorize(request) {
|
|
499
716
|
if (runtime.kind === "unconfigured")
|
|
500
717
|
return { ok: true };
|
|
718
|
+
const startedAt = nowMs();
|
|
501
719
|
const token = parseBearerToken(request);
|
|
502
720
|
if (!token) {
|
|
503
721
|
log.info("auth.no_bearer_token", { outcome: "401" });
|
|
@@ -510,6 +728,12 @@ function createRequestAuthorizer(mcp, options = {}) {
|
|
|
510
728
|
} catch (err) {
|
|
511
729
|
if (err instanceof OAuthConfigurationError) {
|
|
512
730
|
log.error("auth.config_error", { ...describeError(err), outcome: "500" });
|
|
731
|
+
recorder?.record({
|
|
732
|
+
tool: null,
|
|
733
|
+
method: "authorize",
|
|
734
|
+
outcome: "auth_config_error",
|
|
735
|
+
durationMs: nowMs() - startedAt
|
|
736
|
+
});
|
|
513
737
|
return { ok: false, response: oauthConfigurationErrorResponse() };
|
|
514
738
|
}
|
|
515
739
|
if (err instanceof OAuthTokenError) {
|
|
@@ -606,214 +830,6 @@ function corsPreflightResponse(allowMethods) {
|
|
|
606
830
|
});
|
|
607
831
|
}
|
|
608
832
|
|
|
609
|
-
// src/metrics/config.ts
|
|
610
|
-
var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
|
|
611
|
-
var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
|
|
612
|
-
var METRICS_SAMPLE_RATE = 1;
|
|
613
|
-
var METRICS_FLUSH_INTERVAL_MS = 5e3;
|
|
614
|
-
var METRICS_MAX_BATCH_SIZE = 50;
|
|
615
|
-
function assertMetricsEndpoint(endpoint) {
|
|
616
|
-
let url;
|
|
617
|
-
try {
|
|
618
|
-
url = new URL(endpoint);
|
|
619
|
-
} catch {
|
|
620
|
-
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
|
|
621
|
-
}
|
|
622
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
623
|
-
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
function resolveMetricsConfig(config = true) {
|
|
627
|
-
const options = typeof config === "boolean" ? { enabled: config } : config;
|
|
628
|
-
const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
|
|
629
|
-
assertMetricsEndpoint(endpoint);
|
|
630
|
-
return Object.freeze({
|
|
631
|
-
enabled: options.enabled ?? true,
|
|
632
|
-
endpoint,
|
|
633
|
-
headers: options.headers ?? {},
|
|
634
|
-
apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
|
|
635
|
-
sampleRate: METRICS_SAMPLE_RATE,
|
|
636
|
-
flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
|
|
637
|
-
maxBatchSize: METRICS_MAX_BATCH_SIZE
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// package.json
|
|
642
|
-
var version = "0.15.0";
|
|
643
|
-
|
|
644
|
-
// src/metrics/otlp.ts
|
|
645
|
-
var SCOPE_NAME = "@lovable.dev/mcp-js";
|
|
646
|
-
var EVENT_NAME = "mcp.tool.invocation";
|
|
647
|
-
var SEVERITY_INFO = 9;
|
|
648
|
-
function strAttr(key, value) {
|
|
649
|
-
return { key, value: { stringValue: value } };
|
|
650
|
-
}
|
|
651
|
-
function intAttr(key, value) {
|
|
652
|
-
return { key, value: { intValue: String(Math.round(value)) } };
|
|
653
|
-
}
|
|
654
|
-
function toLogRecord(rec) {
|
|
655
|
-
const attributes = [
|
|
656
|
-
strAttr("event.name", EVENT_NAME),
|
|
657
|
-
strAttr("mcp.method", rec.method),
|
|
658
|
-
strAttr("mcp.outcome", rec.outcome),
|
|
659
|
-
intAttr("mcp.duration_ms", rec.durationMs)
|
|
660
|
-
];
|
|
661
|
-
if (rec.tool !== null)
|
|
662
|
-
attributes.push(strAttr("mcp.tool", rec.tool));
|
|
663
|
-
if (rec.reqBytes !== void 0)
|
|
664
|
-
attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
|
|
665
|
-
if (rec.resBytes !== void 0)
|
|
666
|
-
attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
|
|
667
|
-
return {
|
|
668
|
-
timeUnixNano: rec.timeUnixNano,
|
|
669
|
-
observedTimeUnixNano: rec.timeUnixNano,
|
|
670
|
-
severityNumber: SEVERITY_INFO,
|
|
671
|
-
severityText: "INFO",
|
|
672
|
-
body: { stringValue: EVENT_NAME },
|
|
673
|
-
attributes
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function buildLogsPayload(records, server) {
|
|
677
|
-
return JSON.stringify({
|
|
678
|
-
resourceLogs: [
|
|
679
|
-
{
|
|
680
|
-
resource: {
|
|
681
|
-
attributes: [
|
|
682
|
-
strAttr("service.name", server.name),
|
|
683
|
-
strAttr("service.version", server.version),
|
|
684
|
-
strAttr("telemetry.sdk.name", SCOPE_NAME),
|
|
685
|
-
strAttr("telemetry.sdk.version", version),
|
|
686
|
-
strAttr("telemetry.sdk.language", "webjs")
|
|
687
|
-
]
|
|
688
|
-
},
|
|
689
|
-
scopeLogs: [
|
|
690
|
-
{
|
|
691
|
-
scope: { name: SCOPE_NAME, version },
|
|
692
|
-
logRecords: records.map(toLogRecord)
|
|
693
|
-
}
|
|
694
|
-
]
|
|
695
|
-
}
|
|
696
|
-
]
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
function nowUnixNano() {
|
|
700
|
-
return `${Date.now()}000000`;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
// src/metrics/recorder.ts
|
|
704
|
-
function nowMs() {
|
|
705
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
706
|
-
}
|
|
707
|
-
var NOOP_RECORDER = {
|
|
708
|
-
record() {
|
|
709
|
-
},
|
|
710
|
-
async flush() {
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
function createNoopRecorder() {
|
|
714
|
-
return NOOP_RECORDER;
|
|
715
|
-
}
|
|
716
|
-
function readRuntimeEnv(name) {
|
|
717
|
-
try {
|
|
718
|
-
const denoEnv = globalThis.Deno?.env;
|
|
719
|
-
const value = denoEnv?.get?.(name);
|
|
720
|
-
if (value)
|
|
721
|
-
return value;
|
|
722
|
-
} catch {
|
|
723
|
-
}
|
|
724
|
-
try {
|
|
725
|
-
if (typeof process !== "undefined") {
|
|
726
|
-
const value = process.env?.[name];
|
|
727
|
-
if (value)
|
|
728
|
-
return value;
|
|
729
|
-
}
|
|
730
|
-
} catch {
|
|
731
|
-
}
|
|
732
|
-
return void 0;
|
|
733
|
-
}
|
|
734
|
-
function probeWaitUntil() {
|
|
735
|
-
const fn = globalThis.EdgeRuntime?.waitUntil;
|
|
736
|
-
return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
|
|
737
|
-
}
|
|
738
|
-
function createMetricsRecorder(ctx, deps = {}) {
|
|
739
|
-
const { config, server } = ctx;
|
|
740
|
-
if (!config.enabled)
|
|
741
|
-
return NOOP_RECORDER;
|
|
742
|
-
const doFetch = deps.fetch ?? globalThis.fetch;
|
|
743
|
-
if (!doFetch)
|
|
744
|
-
return NOOP_RECORDER;
|
|
745
|
-
const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
|
|
746
|
-
const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
|
|
747
|
-
if (usesLovableEndpoint && !apiKey) {
|
|
748
|
-
log.debug("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar });
|
|
749
|
-
return NOOP_RECORDER;
|
|
750
|
-
}
|
|
751
|
-
const waitUntil = deps.waitUntil ?? probeWaitUntil();
|
|
752
|
-
const buffer = [];
|
|
753
|
-
let timer;
|
|
754
|
-
const schedule = (p) => {
|
|
755
|
-
if (waitUntil) {
|
|
756
|
-
try {
|
|
757
|
-
waitUntil(p);
|
|
758
|
-
return;
|
|
759
|
-
} catch {
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
void p.catch(() => {
|
|
763
|
-
});
|
|
764
|
-
};
|
|
765
|
-
const headers = {};
|
|
766
|
-
if (!usesLovableEndpoint) {
|
|
767
|
-
for (const [key, value] of Object.entries(config.headers)) {
|
|
768
|
-
if (key.toLowerCase() !== "content-type")
|
|
769
|
-
headers[key] = value;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
headers["content-type"] = "application/json";
|
|
773
|
-
if (apiKey)
|
|
774
|
-
headers.authorization = `Bearer ${apiKey}`;
|
|
775
|
-
const flush = async () => {
|
|
776
|
-
if (buffer.length === 0)
|
|
777
|
-
return;
|
|
778
|
-
const records = buffer.splice(0, buffer.length);
|
|
779
|
-
try {
|
|
780
|
-
const res = await doFetch(config.endpoint, {
|
|
781
|
-
method: "POST",
|
|
782
|
-
headers,
|
|
783
|
-
body: buildLogsPayload(records, server),
|
|
784
|
-
keepalive: true
|
|
785
|
-
});
|
|
786
|
-
if (!res.ok)
|
|
787
|
-
log.debug("metrics.flush_rejected", { status: res.status });
|
|
788
|
-
} catch (err) {
|
|
789
|
-
log.debug("metrics.flush_failed", describeError(err));
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
const ensureTimer = () => {
|
|
793
|
-
if (timer !== void 0)
|
|
794
|
-
return;
|
|
795
|
-
timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
|
|
796
|
-
timer.unref?.();
|
|
797
|
-
};
|
|
798
|
-
return {
|
|
799
|
-
record(ev) {
|
|
800
|
-
if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
|
|
801
|
-
return;
|
|
802
|
-
buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
|
|
803
|
-
ensureTimer();
|
|
804
|
-
if (buffer.length >= config.maxBatchSize)
|
|
805
|
-
schedule(flush());
|
|
806
|
-
},
|
|
807
|
-
flush
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
function createRecorderForRuntime(mcp) {
|
|
811
|
-
const config = resolveMetricsConfig(mcp.metrics);
|
|
812
|
-
if (!config.enabled)
|
|
813
|
-
return createNoopRecorder();
|
|
814
|
-
return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
|
|
815
|
-
}
|
|
816
|
-
|
|
817
833
|
// src/protocols/mcp/protocol.ts
|
|
818
834
|
function adaptToolToSdkCallback(tool, auth, recorder) {
|
|
819
835
|
return async (first) => {
|
|
@@ -823,14 +839,24 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
|
|
|
823
839
|
try {
|
|
824
840
|
result = await tool.handler(args, new ToolContext(auth));
|
|
825
841
|
} catch {
|
|
826
|
-
recorder
|
|
842
|
+
reportInvocation(recorder, {
|
|
843
|
+
tool: tool.name,
|
|
844
|
+
method: "tools/call",
|
|
845
|
+
outcome: "handler_error",
|
|
846
|
+
durationMs: nowMs() - start
|
|
847
|
+
});
|
|
827
848
|
return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
|
|
828
849
|
}
|
|
829
850
|
if (result == null) {
|
|
830
|
-
recorder
|
|
851
|
+
reportInvocation(recorder, {
|
|
852
|
+
tool: tool.name,
|
|
853
|
+
method: "tools/call",
|
|
854
|
+
outcome: "handler_error",
|
|
855
|
+
durationMs: nowMs() - start
|
|
856
|
+
});
|
|
831
857
|
return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
|
|
832
858
|
}
|
|
833
|
-
recorder
|
|
859
|
+
reportInvocation(recorder, {
|
|
834
860
|
tool: tool.name,
|
|
835
861
|
method: "tools/call",
|
|
836
862
|
outcome: result.isError ? "tool_error" : "ok",
|
|
@@ -840,7 +866,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
|
|
|
840
866
|
};
|
|
841
867
|
}
|
|
842
868
|
function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
|
|
843
|
-
const authorizer = createRequestAuthorizer(mcp, options);
|
|
869
|
+
const authorizer = createRequestAuthorizer(mcp, options, recorder);
|
|
844
870
|
const handle = async (request) => {
|
|
845
871
|
const authResult = await authorizer.authorize(request);
|
|
846
872
|
if (!authResult.ok)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-COY42xux.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../recorder-
|
|
3
|
+
import { M as MetricsRecorder } from '../../recorder-qlzUKFxG.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type McpProtocolHandler = (request: Request) => Promise<Response>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { M as McpRuntimeOptions } from '../../authorize-BMeXd_Sh.js';
|
|
2
2
|
import { d as McpDefinition } from '../../types-COY42xux.js';
|
|
3
|
-
import { M as MetricsRecorder } from '../../recorder-
|
|
3
|
+
import { M as MetricsRecorder } from '../../recorder-qlzUKFxG.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type McpProtocolHandler = (request: Request) => Promise<Response>;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpProtocolHandler
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
7
|
-
import "../../chunk-QC3DXQTH.js";
|
|
3
|
+
} from "../../chunk-EZQVUNXB.js";
|
|
4
|
+
import "../../chunk-MA5H6PSF.js";
|
|
5
|
+
import "../../chunk-H6BKTNJY.js";
|
|
6
|
+
import "../../chunk-DCWYK4CA.js";
|
|
8
7
|
import "../../chunk-6DXGZZA4.js";
|
|
9
|
-
import "../../chunk-
|
|
8
|
+
import "../../chunk-SKSKC747.js";
|
|
10
9
|
export {
|
|
11
10
|
createMcpProtocolHandler
|
|
12
11
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createOAuthProtectedResourceMetadataHandler
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-T24Z753F.js";
|
|
4
|
+
import "../chunk-H6BKTNJY.js";
|
|
5
|
+
import "../chunk-DCWYK4CA.js";
|
|
6
6
|
import "../chunk-6DXGZZA4.js";
|
|
7
|
+
import "../chunk-SKSKC747.js";
|
|
7
8
|
export {
|
|
8
9
|
createOAuthProtectedResourceMetadataHandler
|
|
9
10
|
};
|