@lovable.dev/mcp-js 0.29.0-rc.0 → 0.29.0-rc.2

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 (65) hide show
  1. package/README.internal.md +22 -31
  2. package/README.md +23 -13
  3. package/dist/{authorize-BjNE3LPr.d.ts → authorize-Bpz8oxjF.d.ts} +2 -5
  4. package/dist/{authorize-BzZFS0zi.d.cts → authorize-Cqr7Jps0.d.cts} +2 -5
  5. package/dist/cli/extract-manifest.cjs +25 -3
  6. package/dist/cli/extract-manifest.js +24 -2
  7. package/dist/{cors-D4YbODs-.js → cors-C_VffY86.js} +15 -21
  8. package/dist/{cors-CmKzDN7k.cjs → cors-DNzLB6qa.cjs} +14 -26
  9. package/dist/{errors-DSe96Ffd.js → errors-Bwd1L0Rf.js} +23 -8
  10. package/dist/{errors-CN6Da8iz.cjs → errors-Cr95rSkB.cjs} +23 -8
  11. package/dist/index.cjs +1 -1
  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/{io-CvALf9NE.d.ts → io-Bh_WpbxU.d.cts} +1 -1
  16. package/dist/{io-BEwvgN8s.d.cts → io-DrHivYt0.d.ts} +1 -1
  17. package/dist/mcp-Bl7pQYdv.js +346 -0
  18. package/dist/mcp-CRdT2Fai.cjs +351 -0
  19. package/dist/{package-DzB_5Hur.js → package-CYA-5C24.js} +1 -1
  20. package/dist/{package-C3YVYgxp.cjs → package-DNSwCau1.cjs} +1 -1
  21. package/dist/protocols/mcp/index.cjs +1 -1
  22. package/dist/protocols/mcp/index.d.cts +36 -3
  23. package/dist/protocols/mcp/index.d.ts +36 -3
  24. package/dist/protocols/mcp/index.js +1 -1
  25. package/dist/protocols/oauth-metadata.cjs +1 -1
  26. package/dist/protocols/oauth-metadata.d.cts +2 -2
  27. package/dist/protocols/oauth-metadata.d.ts +2 -2
  28. package/dist/protocols/oauth-metadata.js +1 -1
  29. package/dist/stacks/supabase/index.cjs +6 -35
  30. package/dist/stacks/supabase/index.d.cts +1 -4
  31. package/dist/stacks/supabase/index.d.ts +1 -4
  32. package/dist/stacks/supabase/index.js +6 -35
  33. package/dist/stacks/supabase/vite.cjs +1 -1
  34. package/dist/stacks/supabase/vite.d.cts +1 -1
  35. package/dist/stacks/supabase/vite.d.ts +1 -1
  36. package/dist/stacks/supabase/vite.js +1 -1
  37. package/dist/stacks/tanstack/index.cjs +2 -23
  38. package/dist/stacks/tanstack/index.d.cts +3 -20
  39. package/dist/stacks/tanstack/index.d.ts +3 -20
  40. package/dist/stacks/tanstack/index.js +3 -22
  41. package/dist/stacks/tanstack/vite.cjs +5 -33
  42. package/dist/stacks/tanstack/vite.d.cts +5 -32
  43. package/dist/stacks/tanstack/vite.d.ts +5 -32
  44. package/dist/stacks/tanstack/vite.js +5 -33
  45. package/dist/{types-D1cgsnPu.d.cts → types-DnGEKnvI.d.cts} +43 -20
  46. package/dist/{types-D1cgsnPu.d.ts → types-DnGEKnvI.d.ts} +43 -20
  47. package/package.json +4 -11
  48. package/dist/base-DSH8NnPj.d.cts +0 -36
  49. package/dist/base-DSH8NnPj.d.ts +0 -36
  50. package/dist/gate-n_HX6eQ5.cjs +0 -26
  51. package/dist/gate-pGsVlY_4.js +0 -21
  52. package/dist/list-tools-Dkyyje7j.cjs +0 -48
  53. package/dist/list-tools-ePP9tXND.js +0 -37
  54. package/dist/list-tools-qIvVJeWZ.d.ts +0 -8
  55. package/dist/list-tools-zagoI477.d.cts +0 -8
  56. package/dist/mcp-Cs4zfvSi.js +0 -336
  57. package/dist/mcp-DQ1Vdv4v.cjs +0 -341
  58. package/dist/protocols/rest/index.cjs +0 -5
  59. package/dist/protocols/rest/index.d.cts +0 -9
  60. package/dist/protocols/rest/index.d.ts +0 -9
  61. package/dist/protocols/rest/index.js +0 -3
  62. package/dist/rest-DSclWpIt.js +0 -129
  63. package/dist/rest-P6XZWP42.cjs +0 -134
  64. package/dist/tool-result-CK6hXO43.cjs +0 -89
  65. package/dist/tool-result-DfCk445b.js +0 -78
@@ -0,0 +1,351 @@
1
+ const require_logger = require("./logger-CN1q-KNn.cjs");
2
+ const require_schema = require("./schema-D3vClxb7.cjs");
3
+ const require_errors = require("./errors-Cr95rSkB.cjs");
4
+ const require_cors = require("./cors-DNzLB6qa.cjs");
5
+ let _modelcontextprotocol_sdk_server_zod_compat_js = require("@modelcontextprotocol/sdk/server/zod-compat.js");
6
+ let _modelcontextprotocol_server = require("@modelcontextprotocol/server");
7
+ //#region src/core/content.ts
8
+ /** Join the text of a result's `type: "text"` blocks into one string, dropping
9
+ * binary/resource blocks. Used to surface a `tool_error` message in the local
10
+ * log; never sent over the telemetry wire. Returns undefined when there is no
11
+ * text to show. */
12
+ function extractTextContent(content) {
13
+ if (!content) return void 0;
14
+ const text = content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
15
+ return text.length > 0 ? text : void 0;
16
+ }
17
+ //#endregion
18
+ //#region src/core/tool-result.ts
19
+ function normalizeResourceLinkIcon(icon) {
20
+ if (typeof icon.sizes !== "string") return icon;
21
+ const { sizes, ...rest } = icon;
22
+ const normalized = sizes.trim();
23
+ return normalized === "" ? rest : {
24
+ ...rest,
25
+ sizes: normalized.split(/\s+/)
26
+ };
27
+ }
28
+ function normalizeToolContent(content) {
29
+ return (content ?? []).map((block) => {
30
+ if (block.type !== "resource_link" || block.icons === void 0) return block;
31
+ return {
32
+ ...block,
33
+ icons: block.icons.map(normalizeResourceLinkIcon)
34
+ };
35
+ });
36
+ }
37
+ function outputValidationError(text) {
38
+ return {
39
+ content: [{
40
+ type: "text",
41
+ text
42
+ }],
43
+ isError: true
44
+ };
45
+ }
46
+ function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
47
+ if (value === null || typeof value === "boolean" || typeof value === "string") return true;
48
+ if (typeof value === "number") return Number.isFinite(value);
49
+ if (typeof value !== "object" || ancestors.has(value)) return false;
50
+ const prototype = Object.getPrototypeOf(value);
51
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) return false;
52
+ ancestors.add(value);
53
+ const valid = (Array.isArray(value) ? value : Object.values(value).filter((entry) => entry !== void 0)).every((entry) => isJsonValue(entry, ancestors));
54
+ ancestors.delete(value);
55
+ return valid;
56
+ }
57
+ async function finalizeToolResult(tool, result) {
58
+ const content = normalizeToolContent(result.content);
59
+ let structuredContent = result.structuredContent;
60
+ if (tool.outputSchema && !result.isError) {
61
+ if (structuredContent === void 0) return outputValidationError(`Output validation error: Tool ${tool.name} has an output schema but no structured content was provided`);
62
+ try {
63
+ const parsed = await (0, _modelcontextprotocol_sdk_server_zod_compat_js.safeParseAsync)(require_schema.schemaFromDefinition(tool.outputSchema), structuredContent);
64
+ if (!parsed.success) return outputValidationError(`Output validation error: Invalid structured content for tool ${tool.name}: ${(0, _modelcontextprotocol_sdk_server_zod_compat_js.getParseErrorMessage)(parsed.error)}`);
65
+ structuredContent = parsed.data;
66
+ } catch {
67
+ return outputValidationError(`Output validation error: Could not validate structured content for tool ${tool.name}`);
68
+ }
69
+ }
70
+ if (structuredContent !== void 0 && !isJsonValue(structuredContent)) {
71
+ if (!result.isError) return outputValidationError(`Output validation error: Tool ${tool.name} returned a non-JSON structured value`);
72
+ structuredContent = void 0;
73
+ }
74
+ if (structuredContent !== void 0 && (structuredContent === null || typeof structuredContent !== "object" || Array.isArray(structuredContent)) && !content.some((block) => block.type === "text")) content.push({
75
+ type: "text",
76
+ text: JSON.stringify(structuredContent)
77
+ });
78
+ return {
79
+ content,
80
+ structuredContent,
81
+ isError: result.isError
82
+ };
83
+ }
84
+ //#endregion
85
+ //#region src/protocols/gate.ts
86
+ function createGatedHandler(gate) {
87
+ const allow = [...gate.methods, "OPTIONS"].join(", ");
88
+ const respond = async (request, recorder) => {
89
+ const authResult = await gate.authorizer.authorize(request, recorder);
90
+ if (!authResult.ok) return authResult.response;
91
+ if (!gate.methods.includes(request.method)) return gate.methodNotAllowed(allow);
92
+ return gate.handle(request, authResult, recorder);
93
+ };
94
+ return async (request, recorder = require_cors.createNoopRecorder()) => {
95
+ const cors = require_cors.evaluateCors(request, gate.allowedOrigins);
96
+ if (!cors.ok) {
97
+ require_logger.log.info("cors.origin_rejected", {
98
+ origin: request.headers.get("Origin"),
99
+ httpMethod: request.method
100
+ });
101
+ await recorder.emit({
102
+ tool: null,
103
+ method: "authorize",
104
+ outcome: "origin_rejected",
105
+ httpMethod: request.method,
106
+ durationMs: 0
107
+ });
108
+ return require_cors.finalizeWireResponse(request, cors.response);
109
+ }
110
+ if (request.method === "OPTIONS") return cors.preflight(allow);
111
+ const final = require_cors.finalizeWireResponse(request, cors.withHeaders(await respond(request, recorder)));
112
+ if (!final.headers.has("Cache-Control")) final.headers.set("Cache-Control", "no-store");
113
+ return final;
114
+ };
115
+ }
116
+ //#endregion
117
+ //#region src/protocols/mcp/protocol.ts
118
+ const MODERN_PROTOCOL_VERSION = "2026-07-28";
119
+ function statelessMethodNotAllowed(allow) {
120
+ return Response.json({
121
+ jsonrpc: "2.0",
122
+ id: null,
123
+ error: {
124
+ code: -32e3,
125
+ message: "Method not allowed: stateless server offers no standalone SSE stream (GET) or session (DELETE)."
126
+ }
127
+ }, {
128
+ status: 405,
129
+ headers: { Allow: allow }
130
+ });
131
+ }
132
+ function zodIssues(error) {
133
+ const issues = error?.issues;
134
+ if (!Array.isArray(issues)) return [{ message: String(error) }];
135
+ return issues.map((issue) => {
136
+ const value = issue;
137
+ return {
138
+ message: typeof value.message === "string" ? value.message : String(value.message),
139
+ ...Array.isArray(value.path) ? { path: value.path } : {}
140
+ };
141
+ });
142
+ }
143
+ function standardSchemaFromDefinition(definition) {
144
+ const schema = require_schema.schemaFromDefinition(definition);
145
+ return { "~standard": {
146
+ version: 1,
147
+ vendor: "zod",
148
+ validate: async (value) => {
149
+ const parsed = await (0, _modelcontextprotocol_sdk_server_zod_compat_js.safeParseAsync)(schema, value);
150
+ return parsed.success ? { value: parsed.data } : { issues: zodIssues(parsed.error) };
151
+ },
152
+ jsonSchema: {
153
+ input: () => require_schema.jsonSchemaFromDefinition(definition, "input"),
154
+ output: () => require_schema.jsonSchemaFromDefinition(definition, "output")
155
+ }
156
+ } };
157
+ }
158
+ function isPlainObject(value) {
159
+ return typeof value === "object" && value !== null && !Array.isArray(value);
160
+ }
161
+ function toolRequestContext(sdkCtx, protocol) {
162
+ const mcpReq = sdkCtx?.mcpReq;
163
+ const client = { protocol };
164
+ const envelope = mcpReq?.envelope;
165
+ const info = envelope?.[_modelcontextprotocol_server.CLIENT_INFO_META_KEY];
166
+ if (isPlainObject(info) && typeof info.name === "string" && typeof info.version === "string") client.info = info;
167
+ const capabilities = envelope?.[_modelcontextprotocol_server.CLIENT_CAPABILITIES_META_KEY];
168
+ if (isPlainObject(capabilities)) {
169
+ client.capabilities = capabilities;
170
+ if (isPlainObject(capabilities.extensions)) client.extensions = capabilities.extensions;
171
+ }
172
+ const progressToken = (mcpReq?._meta)?.progressToken;
173
+ const notify = mcpReq?.notify;
174
+ const sendProgress = progressToken !== void 0 && notify ? async (update) => {
175
+ try {
176
+ await notify({
177
+ method: "notifications/progress",
178
+ params: {
179
+ progressToken,
180
+ ...update
181
+ }
182
+ });
183
+ } catch (err) {
184
+ require_logger.log.debug("mcp.progress_notify_failed", require_logger.describeError(err));
185
+ }
186
+ } : void 0;
187
+ return {
188
+ signal: mcpReq?.signal,
189
+ client,
190
+ sendProgress
191
+ };
192
+ }
193
+ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
194
+ const endUserId = auth?.principal.sub;
195
+ const start = require_cors.nowMs();
196
+ let result;
197
+ try {
198
+ result = await tool.handler(args, new require_errors.ToolContext(auth, toolRequestContext(sdkCtx, protocol)));
199
+ } catch (err) {
200
+ const callerMessage = require_errors.resolveToolErrorMessage(err);
201
+ if (callerMessage === void 0) {
202
+ await recorder.emit({
203
+ tool: tool.name,
204
+ method: "tools/call",
205
+ outcome: "handler_error",
206
+ durationMs: require_cors.nowMs() - start,
207
+ errorText: require_errors.errorSummary(err),
208
+ endUserId,
209
+ protocol
210
+ });
211
+ return finalizeToolResult(tool, {
212
+ content: [{
213
+ type: "text",
214
+ text: "tool execution failed"
215
+ }],
216
+ isError: true
217
+ });
218
+ }
219
+ result = {
220
+ content: [{
221
+ type: "text",
222
+ text: callerMessage
223
+ }],
224
+ isError: true
225
+ };
226
+ }
227
+ if (result == null) {
228
+ await recorder.emit({
229
+ tool: tool.name,
230
+ method: "tools/call",
231
+ outcome: "handler_error",
232
+ durationMs: require_cors.nowMs() - start,
233
+ endUserId,
234
+ protocol
235
+ });
236
+ return finalizeToolResult(tool, {
237
+ content: [{
238
+ type: "text",
239
+ text: `tool "${tool.name}" returned no result`
240
+ }],
241
+ isError: true
242
+ });
243
+ }
244
+ result = await finalizeToolResult(tool, result);
245
+ await recorder.emit({
246
+ tool: tool.name,
247
+ method: "tools/call",
248
+ outcome: result.isError ? "tool_error" : "ok",
249
+ durationMs: require_cors.nowMs() - start,
250
+ errorText: result.isError ? extractTextContent(result.content) : void 0,
251
+ endUserId,
252
+ protocol
253
+ });
254
+ return result;
255
+ }
256
+ function adaptToolCallback(tool, auth, recorder, protocol) {
257
+ return async (first, second) => {
258
+ const sdkCtx = tool.inputSchema ? second : first;
259
+ const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx);
260
+ return {
261
+ content: result.content ?? [],
262
+ structuredContent: result.structuredContent,
263
+ isError: result.isError
264
+ };
265
+ };
266
+ }
267
+ function buildServer(mcp, auth, recorder, era) {
268
+ const server = new _modelcontextprotocol_server.McpServer({
269
+ name: mcp.name,
270
+ version: mcp.version,
271
+ title: mcp.title
272
+ }, {
273
+ instructions: mcp.instructions,
274
+ capabilities: { tools: { listChanged: false } }
275
+ });
276
+ for (const tool of mcp.tools) {
277
+ const config = {
278
+ title: tool.title,
279
+ description: tool.description,
280
+ annotations: tool.annotations,
281
+ ...tool.outputSchema ? { outputSchema: standardSchemaFromDefinition(tool.outputSchema) } : {}
282
+ };
283
+ const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION);
284
+ if (tool.inputSchema) server.registerTool(tool.name, {
285
+ ...config,
286
+ inputSchema: standardSchemaFromDefinition(tool.inputSchema)
287
+ }, callback);
288
+ else server.registerTool(tool.name, config, callback);
289
+ }
290
+ return server;
291
+ }
292
+ /**
293
+ * Build a Web-Standard request handler that serves the MCP protocol over
294
+ * streamable HTTP. A fresh `McpServer` + transport is constructed per
295
+ * request — the transport is stateless, so this is cheap and there is no
296
+ * cross-request state to leak. The per-request `recorder` is supplied by the
297
+ * caller (the stack handler) so telemetry reads the runtime env in-flight.
298
+ */
299
+ function createMcpProtocolHandler(mcp, options = {}) {
300
+ const authorizer = require_cors.createRequestAuthorizer(mcp, options);
301
+ const handle = async (request, authResult, recorder) => {
302
+ let protocolError;
303
+ const reportTransportError = async (error) => {
304
+ await recorder.emit({
305
+ tool: null,
306
+ method: "transport",
307
+ outcome: "transport_error",
308
+ durationMs: 0,
309
+ endUserId: authResult.auth?.principal.sub
310
+ });
311
+ require_logger.log.error("mcp.transport_error", {
312
+ ...error === void 0 ? {} : require_logger.describeError(error),
313
+ outcome: "500 internal error"
314
+ });
315
+ };
316
+ try {
317
+ const response = await (0, _modelcontextprotocol_server.createMcpHandler)(({ era }) => buildServer(mcp, authResult.auth, recorder, era), {
318
+ legacy: "stateless",
319
+ onerror: (error) => {
320
+ protocolError = error;
321
+ }
322
+ }).fetch(request);
323
+ if (response.status >= 500) await reportTransportError(protocolError);
324
+ return response;
325
+ } catch (err) {
326
+ await reportTransportError(err);
327
+ return Response.json({
328
+ jsonrpc: "2.0",
329
+ id: null,
330
+ error: {
331
+ code: -32603,
332
+ message: "internal error"
333
+ }
334
+ }, { status: 500 });
335
+ }
336
+ };
337
+ return createGatedHandler({
338
+ authorizer,
339
+ allowedOrigins: mcp.allowedOrigins,
340
+ methods: ["POST"],
341
+ methodNotAllowed: statelessMethodNotAllowed,
342
+ handle
343
+ });
344
+ }
345
+ //#endregion
346
+ Object.defineProperty(exports, "createMcpProtocolHandler", {
347
+ enumerable: true,
348
+ get: function() {
349
+ return createMcpProtocolHandler;
350
+ }
351
+ });
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.29.0-rc.0";
2
+ var version = "0.29.0-rc.2";
3
3
  //#endregion
4
4
  export { version as t };
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.29.0-rc.0";
2
+ var version = "0.29.0-rc.2";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_mcp = require("../../mcp-DQ1Vdv4v.cjs");
2
+ const require_mcp = require("../../mcp-CRdT2Fai.cjs");
3
3
  exports.createMcpProtocolHandler = require_mcp.createMcpProtocolHandler;
@@ -1,6 +1,39 @@
1
- import { u as McpDefinition } from "../../types-D1cgsnPu.cjs";
2
- import { t as MetricsRecorder } from "../../base-DSH8NnPj.cjs";
3
- import { t as McpRuntimeOptions } from "../../authorize-BzZFS0zi.cjs";
1
+ import { u as McpDefinition } from "../../types-DnGEKnvI.cjs";
2
+ import { t as McpRuntimeOptions } from "../../authorize-Cqr7Jps0.cjs";
3
+ //#region src/metrics/impl/base.d.ts
4
+ type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_challenge" | "origin_rejected" | "auth_discovery_config_error" | "auth_discovery_unreachable" | "auth_jwks_config_error" | "auth_jwks_unreachable";
5
+ /** One recorded MCP call. Carries no arguments or response payloads — only the
6
+ * tool name, the JSON-RPC method, the result class, timing, and byte sizes.
7
+ * `errorText` is the sole exception: it is logged locally for debugging and
8
+ * deliberately never included in the OTLP payload (see `emit` / `buildLogsPayload`). */
9
+ interface InvocationRecord {
10
+ /** Tool name for `tools/call`; `null` for list/initialize, transport faults, and `authorize` records. */
11
+ tool: string | null;
12
+ /** JSON-RPC method, e.g. `tools/call`; `authorize` for records from the authorization gate. */
13
+ method: string;
14
+ outcome: InvocationOutcome;
15
+ durationMs: number;
16
+ reqBytes?: number;
17
+ resBytes?: number;
18
+ /** HTTP request method. Set on `auth_challenge` so probe traffic (GET vs
19
+ * POST discovery) is distinguishable; absent on tool-call records. */
20
+ httpMethod?: string;
21
+ /** Wire surface that served the call; absent on records emitted before
22
+ * protocol classification (auth gate, transport faults). */
23
+ protocol?: "2026-07-28" | "legacy";
24
+ /** The app end-user that made the call (the access token `sub`), or
25
+ * `undefined` when the request is unauthenticated. Not a Lovable identity. */
26
+ endUserId?: string;
27
+ /** Caller-visible `isError` text (`tool_error`) or a bounded internal-exception
28
+ * summary (`handler_error`). Local log only — never sent to the collector. */
29
+ errorText?: string;
30
+ }
31
+ /** A per-request telemetry recorder. `emit` logs the invocation and sends it as a
32
+ * single OTLP POST, awaited so it lands before the request ends. */
33
+ interface MetricsRecorder {
34
+ emit(ev: InvocationRecord): Promise<void>;
35
+ }
36
+ //#endregion
4
37
  //#region src/protocols/mcp/protocol.d.ts
5
38
  type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
6
39
  /**
@@ -1,6 +1,39 @@
1
- import { u as McpDefinition } from "../../types-D1cgsnPu.js";
2
- import { t as MetricsRecorder } from "../../base-DSH8NnPj.js";
3
- import { t as McpRuntimeOptions } from "../../authorize-BjNE3LPr.js";
1
+ import { u as McpDefinition } from "../../types-DnGEKnvI.js";
2
+ import { t as McpRuntimeOptions } from "../../authorize-Bpz8oxjF.js";
3
+ //#region src/metrics/impl/base.d.ts
4
+ type InvocationOutcome = "ok" | "tool_error" | "handler_error" | "transport_error" | "auth_challenge" | "origin_rejected" | "auth_discovery_config_error" | "auth_discovery_unreachable" | "auth_jwks_config_error" | "auth_jwks_unreachable";
5
+ /** One recorded MCP call. Carries no arguments or response payloads — only the
6
+ * tool name, the JSON-RPC method, the result class, timing, and byte sizes.
7
+ * `errorText` is the sole exception: it is logged locally for debugging and
8
+ * deliberately never included in the OTLP payload (see `emit` / `buildLogsPayload`). */
9
+ interface InvocationRecord {
10
+ /** Tool name for `tools/call`; `null` for list/initialize, transport faults, and `authorize` records. */
11
+ tool: string | null;
12
+ /** JSON-RPC method, e.g. `tools/call`; `authorize` for records from the authorization gate. */
13
+ method: string;
14
+ outcome: InvocationOutcome;
15
+ durationMs: number;
16
+ reqBytes?: number;
17
+ resBytes?: number;
18
+ /** HTTP request method. Set on `auth_challenge` so probe traffic (GET vs
19
+ * POST discovery) is distinguishable; absent on tool-call records. */
20
+ httpMethod?: string;
21
+ /** Wire surface that served the call; absent on records emitted before
22
+ * protocol classification (auth gate, transport faults). */
23
+ protocol?: "2026-07-28" | "legacy";
24
+ /** The app end-user that made the call (the access token `sub`), or
25
+ * `undefined` when the request is unauthenticated. Not a Lovable identity. */
26
+ endUserId?: string;
27
+ /** Caller-visible `isError` text (`tool_error`) or a bounded internal-exception
28
+ * summary (`handler_error`). Local log only — never sent to the collector. */
29
+ errorText?: string;
30
+ }
31
+ /** A per-request telemetry recorder. `emit` logs the invocation and sends it as a
32
+ * single OTLP POST, awaited so it lands before the request ends. */
33
+ interface MetricsRecorder {
34
+ emit(ev: InvocationRecord): Promise<void>;
35
+ }
36
+ //#endregion
4
37
  //#region src/protocols/mcp/protocol.d.ts
5
38
  type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
6
39
  /**
@@ -1,2 +1,2 @@
1
- import { t as createMcpProtocolHandler } from "../../mcp-Cs4zfvSi.js";
1
+ import { t as createMcpProtocolHandler } from "../../mcp-Bl7pQYdv.js";
2
2
  export { createMcpProtocolHandler };
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_logger = require("../logger-CN1q-KNn.cjs");
3
- const require_cors = require("../cors-CmKzDN7k.cjs");
3
+ const require_cors = require("../cors-DNzLB6qa.cjs");
4
4
  //#region src/protocols/oauth-metadata.ts
5
5
  function notFound() {
6
6
  return new Response(JSON.stringify({ error: "not found" }), {
@@ -1,5 +1,5 @@
1
- import { u as McpDefinition } from "../types-D1cgsnPu.cjs";
2
- import { t as McpRuntimeOptions } from "../authorize-BzZFS0zi.cjs";
1
+ import { u as McpDefinition } from "../types-DnGEKnvI.cjs";
2
+ import { t as McpRuntimeOptions } from "../authorize-Cqr7Jps0.cjs";
3
3
  //#region src/protocols/oauth-metadata.d.ts
4
4
  type OAuthProtectedResourceMetadataHandler = (request: Request) => Promise<Response>;
5
5
  declare function createOAuthProtectedResourceMetadataHandler(mcp: McpDefinition, options?: McpRuntimeOptions): OAuthProtectedResourceMetadataHandler;
@@ -1,5 +1,5 @@
1
- import { u as McpDefinition } from "../types-D1cgsnPu.js";
2
- import { t as McpRuntimeOptions } from "../authorize-BjNE3LPr.js";
1
+ import { u as McpDefinition } from "../types-DnGEKnvI.js";
2
+ import { t as McpRuntimeOptions } from "../authorize-Bpz8oxjF.js";
3
3
  //#region src/protocols/oauth-metadata.d.ts
4
4
  type OAuthProtectedResourceMetadataHandler = (request: Request) => Promise<Response>;
5
5
  declare function createOAuthProtectedResourceMetadataHandler(mcp: McpDefinition, options?: McpRuntimeOptions): OAuthProtectedResourceMetadataHandler;
@@ -1,5 +1,5 @@
1
1
  import { i as log, r as describeError } from "../logger-Ctv5xUSD.js";
2
- import { a as oauthConfigurationErrorResponse, d as JSON_HEADERS, f as finalizeWireResponse, i as getOAuthRuntime, p as methodNotAllowed, s as resolveProtectedResource, t as evaluateCors } from "../cors-D4YbODs-.js";
2
+ import { d as finalizeWireResponse, f as methodNotAllowed, i as oauthConfigurationErrorResponse, o as resolveProtectedResource, r as getOAuthRuntime, t as evaluateCors, u as JSON_HEADERS } from "../cors-C_VffY86.js";
3
3
  //#region src/protocols/oauth-metadata.ts
4
4
  function notFound() {
5
5
  return new Response(JSON.stringify({ error: "not found" }), {
@@ -1,11 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_logger = require("../../logger-CN1q-KNn.cjs");
3
- const require_cors = require("../../cors-CmKzDN7k.cjs");
3
+ const require_cors = require("../../cors-DNzLB6qa.cjs");
4
4
  const require_metadata_path = require("../../metadata-path-zd7NSNoa.cjs");
5
- const require_mcp = require("../../mcp-DQ1Vdv4v.cjs");
5
+ const require_mcp = require("../../mcp-CRdT2Fai.cjs");
6
6
  const require_protocols_oauth_metadata = require("../../protocols/oauth-metadata.cjs");
7
- const require_list_tools = require("../../list-tools-Dkyyje7j.cjs");
8
- const require_rest = require("../../rest-P6XZWP42.cjs");
9
7
  const require_forwarded = require("../../forwarded-BC_RHnn5.cjs");
10
8
  const require_paths = require("../../paths-OP318a6c.cjs");
11
9
  //#region src/stacks/supabase/handler.ts
@@ -15,24 +13,8 @@ function deriveResourcePath(options) {
15
13
  require_paths.assertFunctionName(options.functionName);
16
14
  return `${require_paths.FUNCTIONS_MOUNT_PREFIX}${options.functionName}`;
17
15
  }
18
- function dispatchFor(pathname) {
19
- const path = pathname.length > 1 ? pathname.replace(/\/+$/, "") : pathname;
20
- if (path.endsWith("/.well-known/oauth-protected-resource")) return { kind: "metadata" };
21
- if (path.endsWith("/.mcp/list-tools")) return { kind: "list-tools" };
22
- const invokeMatch = /\/\.mcp\/invoke-tool\/([^/]+)$/.exec(path);
23
- if (invokeMatch) {
24
- let toolName;
25
- try {
26
- toolName = decodeURIComponent(invokeMatch[1]);
27
- } catch {
28
- return { kind: "mcp" };
29
- }
30
- return {
31
- kind: "invoke-tool",
32
- toolName
33
- };
34
- }
35
- return { kind: "mcp" };
16
+ function isMetadataPath(pathname) {
17
+ return (pathname.length > 1 ? pathname.replace(/\/+$/, "") : pathname).endsWith(require_metadata_path.OAUTH_PROTECTED_RESOURCE_METADATA_PATH);
36
18
  }
37
19
  /**
38
20
  * Build a single Web-Standard handler that serves the full MCP surface from
@@ -41,12 +23,9 @@ function dispatchFor(pathname) {
41
23
  * | Suffix | Target |
42
24
  * | --- | --- |
43
25
  * | `/.well-known/oauth-protected-resource` | RFC 9728 metadata |
44
- * | `/.mcp/list-tools` | REST tool catalog |
45
- * | `/.mcp/invoke-tool/<tool>` | REST tool dispatcher |
46
26
  * | (anything else) | MCP streamable-HTTP protocol |
47
27
  *
48
28
  * Pass the handler to `Deno.serve(...)` in the emitted function entry.
49
- * The same OAuth bearer gate protects every dispatch target.
50
29
  */
51
30
  function createSupabaseHandler(mcp, options = {}) {
52
31
  const resourcePath = deriveResourcePath(options);
@@ -62,19 +41,11 @@ function createSupabaseHandler(mcp, options = {}) {
62
41
  trustForwardedProto: true
63
42
  };
64
43
  const mcpHandler = require_mcp.createMcpProtocolHandler(mcp, runtimeOptions);
65
- const listToolsHandler = require_list_tools.createListToolsHandler(mcp, runtimeOptions);
66
- const invokeToolHandler = require_rest.createInvokeToolHandler(mcp, runtimeOptions);
67
44
  const metadataHandler = require_protocols_oauth_metadata.createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
68
45
  return async (request) => {
69
46
  const req = require_forwarded.applyForwardedOrigin(request, runtimeOptions);
70
- const recorder = require_cors.createRecorderForRuntime(mcp, { stack: "supabase" });
71
- const target = dispatchFor(new URL(req.url).pathname);
72
- switch (target.kind) {
73
- case "metadata": return metadataHandler(req);
74
- case "list-tools": return listToolsHandler(req, recorder);
75
- case "invoke-tool": return invokeToolHandler(req, target.toolName, recorder);
76
- case "mcp": return mcpHandler(req, recorder);
77
- }
47
+ if (isMetadataPath(new URL(req.url).pathname)) return metadataHandler(req);
48
+ return mcpHandler(req, require_cors.createRecorderForRuntime(mcp, { stack: "supabase" }));
78
49
  };
79
50
  }
80
51
  //#endregion
@@ -1,4 +1,4 @@
1
- import { u as McpDefinition } from "../../types-D1cgsnPu.cjs";
1
+ import { u as McpDefinition } from "../../types-DnGEKnvI.cjs";
2
2
  //#region src/stacks/supabase/handler.d.ts
3
3
  type SupabaseHandler = (request: Request) => Promise<Response>;
4
4
  interface SupabaseHandlerOptions {
@@ -35,12 +35,9 @@ interface SupabaseHandlerOptions {
35
35
  * | Suffix | Target |
36
36
  * | --- | --- |
37
37
  * | `/.well-known/oauth-protected-resource` | RFC 9728 metadata |
38
- * | `/.mcp/list-tools` | REST tool catalog |
39
- * | `/.mcp/invoke-tool/<tool>` | REST tool dispatcher |
40
38
  * | (anything else) | MCP streamable-HTTP protocol |
41
39
  *
42
40
  * Pass the handler to `Deno.serve(...)` in the emitted function entry.
43
- * The same OAuth bearer gate protects every dispatch target.
44
41
  */
45
42
  declare function createSupabaseHandler(mcp: McpDefinition, options?: SupabaseHandlerOptions): SupabaseHandler;
46
43
  //#endregion
@@ -1,4 +1,4 @@
1
- import { u as McpDefinition } from "../../types-D1cgsnPu.js";
1
+ import { u as McpDefinition } from "../../types-DnGEKnvI.js";
2
2
  //#region src/stacks/supabase/handler.d.ts
3
3
  type SupabaseHandler = (request: Request) => Promise<Response>;
4
4
  interface SupabaseHandlerOptions {
@@ -35,12 +35,9 @@ interface SupabaseHandlerOptions {
35
35
  * | Suffix | Target |
36
36
  * | --- | --- |
37
37
  * | `/.well-known/oauth-protected-resource` | RFC 9728 metadata |
38
- * | `/.mcp/list-tools` | REST tool catalog |
39
- * | `/.mcp/invoke-tool/<tool>` | REST tool dispatcher |
40
38
  * | (anything else) | MCP streamable-HTTP protocol |
41
39
  *
42
40
  * Pass the handler to `Deno.serve(...)` in the emitted function entry.
43
- * The same OAuth bearer gate protects every dispatch target.
44
41
  */
45
42
  declare function createSupabaseHandler(mcp: McpDefinition, options?: SupabaseHandlerOptions): SupabaseHandler;
46
43
  //#endregion