@lovable.dev/mcp-js 0.22.1 → 0.22.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/authorize-CumVyk7p.d.cts +27 -0
  2. package/dist/authorize-D6p4-9_D.d.ts +27 -0
  3. package/dist/base-DCe0kP79.d.cts +29 -0
  4. package/dist/base-DCe0kP79.d.ts +29 -0
  5. package/dist/cli/extract-manifest.cjs +116 -201
  6. package/dist/cli/extract-manifest.d.cts +1 -1
  7. package/dist/cli/extract-manifest.d.ts +1 -1
  8. package/dist/cli/extract-manifest.js +117 -156
  9. package/dist/content-D5LJAHyM.js +12 -0
  10. package/dist/content-NCYIGgOb.cjs +17 -0
  11. package/dist/context-BweeEcoA.cjs +56 -0
  12. package/dist/context-CIpPzN7P.js +51 -0
  13. package/dist/cors-C2n2LxrC.js +830 -0
  14. package/dist/cors-Cga2PWEg.cjs +913 -0
  15. package/dist/forwarded--h4efJy-.js +43 -0
  16. package/dist/forwarded-Pi8Hs5Ps.cjs +48 -0
  17. package/dist/fs-errors-CWNzOV75.cjs +11 -0
  18. package/dist/fs-errors-PA2t1TIp.js +6 -0
  19. package/dist/index.cjs +129 -329
  20. package/dist/index.d.cts +26 -26
  21. package/dist/index.d.ts +26 -26
  22. package/dist/index.js +118 -177
  23. package/dist/{io-D4srzRKc.d.ts → io-CfSPxeBN.d.ts} +6 -4
  24. package/dist/io-DPYvBqET.d.cts +15 -0
  25. package/dist/list-tools-07OV14rK.cjs +57 -0
  26. package/dist/list-tools-B4TTPEl1.d.cts +8 -0
  27. package/dist/list-tools-I8Hvub9P.js +46 -0
  28. package/dist/list-tools-bh6-eqZM.d.ts +8 -0
  29. package/dist/logger-2OXtfiIW.js +141 -0
  30. package/dist/logger-BqPOa_E1.cjs +194 -0
  31. package/dist/mcp-B6z5Givq.js +123 -0
  32. package/dist/mcp-DLv_c1O5.cjs +128 -0
  33. package/dist/metadata-path-CAkNcfyY.js +12 -0
  34. package/dist/metadata-path-zd7NSNoa.cjs +17 -0
  35. package/dist/package-CxQcGWdU.cjs +9 -0
  36. package/dist/package-xS6mk-b_.js +4 -0
  37. package/dist/paths-IS65L6TA.js +7 -0
  38. package/dist/paths-OP318a6c.cjs +18 -0
  39. package/dist/protocols/mcp/index.cjs +3 -750
  40. package/dist/protocols/mcp/index.d.cts +6 -7
  41. package/dist/protocols/mcp/index.d.ts +6 -7
  42. package/dist/protocols/mcp/index.js +2 -12
  43. package/dist/protocols/oauth-metadata.cjs +48 -539
  44. package/dist/protocols/oauth-metadata.d.cts +5 -6
  45. package/dist/protocols/oauth-metadata.d.ts +5 -6
  46. package/dist/protocols/oauth-metadata.js +52 -10
  47. package/dist/protocols/rest/index.cjs +5 -843
  48. package/dist/protocols/rest/index.d.cts +7 -10
  49. package/dist/protocols/rest/index.d.ts +7 -10
  50. package/dist/protocols/rest/index.js +3 -16
  51. package/dist/rest-CggWx00c.js +117 -0
  52. package/dist/rest-DxhK7-3b.cjs +122 -0
  53. package/dist/stacks/supabase/index.cjs +76 -1318
  54. package/dist/stacks/supabase/index.d.cts +29 -30
  55. package/dist/stacks/supabase/index.d.ts +29 -30
  56. package/dist/stacks/supabase/index.js +73 -89
  57. package/dist/stacks/supabase/vite.cjs +258 -287
  58. package/dist/stacks/supabase/vite.d.cts +24 -24
  59. package/dist/stacks/supabase/vite.d.ts +24 -24
  60. package/dist/stacks/supabase/vite.js +252 -252
  61. package/dist/stacks/tanstack/index.cjs +42 -1272
  62. package/dist/stacks/tanstack/index.d.cts +8 -9
  63. package/dist/stacks/tanstack/index.d.ts +8 -9
  64. package/dist/stacks/tanstack/index.js +36 -41
  65. package/dist/stacks/tanstack/vite.cjs +223 -312
  66. package/dist/stacks/tanstack/vite.d.cts +80 -81
  67. package/dist/stacks/tanstack/vite.d.ts +80 -81
  68. package/dist/stacks/tanstack/vite.js +216 -282
  69. package/dist/types-BYdYYTjk.d.cts +321 -0
  70. package/dist/types-BYdYYTjk.d.ts +321 -0
  71. package/package.json +4 -4
  72. package/dist/authorize-BMeXd_Sh.d.ts +0 -25
  73. package/dist/base-CM-KCpp6.d.ts +0 -28
  74. package/dist/chunk-5HVSJCKE.js +0 -114
  75. package/dist/chunk-6DXGZZA4.js +0 -6
  76. package/dist/chunk-6QFZYYUV.js +0 -11
  77. package/dist/chunk-6SZOFKGH.js +0 -58
  78. package/dist/chunk-H37EB22A.js +0 -125
  79. package/dist/chunk-IFDWUM7L.js +0 -741
  80. package/dist/chunk-IXZIFYO6.js +0 -79
  81. package/dist/chunk-MA5H6PSF.js +0 -46
  82. package/dist/chunk-TJN33K5U.js +0 -141
  83. package/dist/chunk-UQK5UO6C.js +0 -26
  84. package/dist/chunk-XQWJN6DC.js +0 -14
  85. package/dist/chunk-Y3ZFPEQH.js +0 -8
  86. package/dist/chunk-ZQXSWTPU.js +0 -6
  87. package/dist/types-qqrmJ736.d.ts +0 -321
@@ -0,0 +1,141 @@
1
+ //#region src/metrics/config.ts
2
+ const DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
3
+ const METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
4
+ /**
5
+ * Validate the ingest endpoint at plugin-construction time so a malformed URL
6
+ * fails the build rather than silently dropping every batch at runtime.
7
+ */
8
+ function assertMetricsEndpoint(endpoint) {
9
+ let url;
10
+ try {
11
+ url = new URL(endpoint);
12
+ } catch {
13
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
14
+ }
15
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
16
+ }
17
+ /**
18
+ * Resolve `boolean | MetricsOptions` into a frozen config. Telemetry is on by
19
+ * default and self-disables at runtime when `LOVABLE_API_KEY` is absent (so a
20
+ * local `vite dev` stays silent); pass `false` to opt out entirely.
21
+ */
22
+ function resolveMetricsConfig(config = true) {
23
+ const options = typeof config === "boolean" ? { enabled: config } : config;
24
+ const endpoint = options.endpoint ?? "https://api.lovable.dev/v1/app-mcp-usage";
25
+ assertMetricsEndpoint(endpoint);
26
+ return Object.freeze({
27
+ enabled: options.enabled ?? true,
28
+ endpoint,
29
+ headers: options.headers ?? {},
30
+ apiKeyEnvVar: METRICS_API_KEY_ENV_VAR
31
+ });
32
+ }
33
+ //#endregion
34
+ //#region src/core/url.ts
35
+ function trimTrailingSlash(value) {
36
+ return value.replace(/\/+$/, "");
37
+ }
38
+ function isLocalHTTPHost(hostname) {
39
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
40
+ }
41
+ /**
42
+ * Shared scheme/credential/query checks for every absolute URL we accept or
43
+ * discover. Returns the human-readable problem suffix so each call site can
44
+ * prefix it with its own subject and throw its own error type.
45
+ */
46
+ function urlSafetyProblem(url) {
47
+ const isAllowedHTTP = url.protocol === "http:" && isLocalHTTPHost(url.hostname);
48
+ if (url.protocol !== "https:" && !isAllowedHTTP) return "must use https://, except localhost development URLs";
49
+ if (url.username || url.password) return "must not include credentials";
50
+ if (url.search || url.hash) return "must not include query or fragment";
51
+ }
52
+ //#endregion
53
+ //#region src/core/validation.ts
54
+ /**
55
+ * Parse `raw` as an absolute URL and reject unsafe shapes (non-HTTPS except
56
+ * localhost, embedded credentials, query/fragment). `subject` is the
57
+ * fully-formed message prefix (e.g. `auth.issuer`, `managed OAuth issuer`) so
58
+ * each call site keeps its own wording; `ErrorClass` selects the thrown type.
59
+ */
60
+ function parseSafeUrl(subject, raw, ErrorClass = Error) {
61
+ let url;
62
+ try {
63
+ url = new URL(raw);
64
+ } catch {
65
+ throw new ErrorClass(`${subject} must be an absolute URL`);
66
+ }
67
+ const problem = urlSafetyProblem(url);
68
+ if (problem) throw new ErrorClass(`${subject} ${problem}`);
69
+ return url;
70
+ }
71
+ //#endregion
72
+ //#region src/core/logger.ts
73
+ const LEVEL_RANK = {
74
+ silent: 0,
75
+ error: 1,
76
+ warn: 2,
77
+ info: 3,
78
+ debug: 4
79
+ };
80
+ function isLogLevel(value) {
81
+ return typeof value === "string" && value in LEVEL_RANK;
82
+ }
83
+ const LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
84
+ function readEnvLevel() {
85
+ try {
86
+ const normalized = (typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0)?.trim().toLowerCase();
87
+ return isLogLevel(normalized) ? normalized : void 0;
88
+ } catch {
89
+ return;
90
+ }
91
+ }
92
+ let currentLevel = readEnvLevel() ?? "debug";
93
+ /**
94
+ * Set the runtime log level programmatically. Use this when the deployment can't
95
+ * surface `LOVABLE_MCP_LOG_LEVEL` to the package (e.g. a Cloudflare Worker that
96
+ * passes vars via bindings): call `setLogLevel("debug")` once at server startup.
97
+ */
98
+ function setLogLevel(level) {
99
+ currentLevel = level;
100
+ }
101
+ /** Parse an env value into a LogLevel, or undefined if it names no valid level. */
102
+ function parseLogLevel(raw) {
103
+ const normalized = raw?.trim().toLowerCase();
104
+ return isLogLevel(normalized) ? normalized : void 0;
105
+ }
106
+ /**
107
+ * Apply the log level from an env value: use it when it names a valid level,
108
+ * otherwise fall back to `debug` so the SDK's diagnostics are on by default.
109
+ */
110
+ function applyLogLevelFromEnv(raw) {
111
+ setLogLevel(parseLogLevel(raw) ?? "debug");
112
+ }
113
+ function enabled(level) {
114
+ return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
115
+ }
116
+ function emit(level, method, event, fields) {
117
+ if (!enabled(level)) return;
118
+ const message = `[mcp-js] ${event}`;
119
+ if (fields) console[method](message, fields);
120
+ else console[method](message);
121
+ }
122
+ const log = {
123
+ error: (event, fields) => emit("error", "error", event, fields),
124
+ warn: (event, fields) => emit("warn", "warn", event, fields),
125
+ info: (event, fields) => emit("info", "info", event, fields),
126
+ debug: (event, fields) => emit("debug", "debug", event, fields)
127
+ };
128
+ /** Non-secret error shape for logs: name, message, and a string `code` (jose carries one) when present. */
129
+ function describeError(err) {
130
+ if (err instanceof Error) {
131
+ const code = err.code;
132
+ return {
133
+ name: err.name,
134
+ message: err.message,
135
+ ...typeof code === "string" ? { code } : {}
136
+ };
137
+ }
138
+ return { value: String(err) };
139
+ }
140
+ //#endregion
141
+ export { setLogLevel as a, DEFAULT_METRICS_ENDPOINT as c, log as i, resolveMetricsConfig as l, applyLogLevelFromEnv as n, parseSafeUrl as o, describeError as r, trimTrailingSlash as s, LOG_LEVEL_ENV_VAR as t };
@@ -0,0 +1,194 @@
1
+ //#region src/metrics/config.ts
2
+ const DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
3
+ const METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
4
+ /**
5
+ * Validate the ingest endpoint at plugin-construction time so a malformed URL
6
+ * fails the build rather than silently dropping every batch at runtime.
7
+ */
8
+ function assertMetricsEndpoint(endpoint) {
9
+ let url;
10
+ try {
11
+ url = new URL(endpoint);
12
+ } catch {
13
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
14
+ }
15
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
16
+ }
17
+ /**
18
+ * Resolve `boolean | MetricsOptions` into a frozen config. Telemetry is on by
19
+ * default and self-disables at runtime when `LOVABLE_API_KEY` is absent (so a
20
+ * local `vite dev` stays silent); pass `false` to opt out entirely.
21
+ */
22
+ function resolveMetricsConfig(config = true) {
23
+ const options = typeof config === "boolean" ? { enabled: config } : config;
24
+ const endpoint = options.endpoint ?? "https://api.lovable.dev/v1/app-mcp-usage";
25
+ assertMetricsEndpoint(endpoint);
26
+ return Object.freeze({
27
+ enabled: options.enabled ?? true,
28
+ endpoint,
29
+ headers: options.headers ?? {},
30
+ apiKeyEnvVar: METRICS_API_KEY_ENV_VAR
31
+ });
32
+ }
33
+ //#endregion
34
+ //#region src/core/url.ts
35
+ function trimTrailingSlash(value) {
36
+ return value.replace(/\/+$/, "");
37
+ }
38
+ function isLocalHTTPHost(hostname) {
39
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
40
+ }
41
+ /**
42
+ * Shared scheme/credential/query checks for every absolute URL we accept or
43
+ * discover. Returns the human-readable problem suffix so each call site can
44
+ * prefix it with its own subject and throw its own error type.
45
+ */
46
+ function urlSafetyProblem(url) {
47
+ const isAllowedHTTP = url.protocol === "http:" && isLocalHTTPHost(url.hostname);
48
+ if (url.protocol !== "https:" && !isAllowedHTTP) return "must use https://, except localhost development URLs";
49
+ if (url.username || url.password) return "must not include credentials";
50
+ if (url.search || url.hash) return "must not include query or fragment";
51
+ }
52
+ //#endregion
53
+ //#region src/core/validation.ts
54
+ /**
55
+ * Parse `raw` as an absolute URL and reject unsafe shapes (non-HTTPS except
56
+ * localhost, embedded credentials, query/fragment). `subject` is the
57
+ * fully-formed message prefix (e.g. `auth.issuer`, `managed OAuth issuer`) so
58
+ * each call site keeps its own wording; `ErrorClass` selects the thrown type.
59
+ */
60
+ function parseSafeUrl(subject, raw, ErrorClass = Error) {
61
+ let url;
62
+ try {
63
+ url = new URL(raw);
64
+ } catch {
65
+ throw new ErrorClass(`${subject} must be an absolute URL`);
66
+ }
67
+ const problem = urlSafetyProblem(url);
68
+ if (problem) throw new ErrorClass(`${subject} ${problem}`);
69
+ return url;
70
+ }
71
+ //#endregion
72
+ //#region src/core/logger.ts
73
+ const LEVEL_RANK = {
74
+ silent: 0,
75
+ error: 1,
76
+ warn: 2,
77
+ info: 3,
78
+ debug: 4
79
+ };
80
+ function isLogLevel(value) {
81
+ return typeof value === "string" && value in LEVEL_RANK;
82
+ }
83
+ const LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
84
+ function readEnvLevel() {
85
+ try {
86
+ const normalized = (typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0)?.trim().toLowerCase();
87
+ return isLogLevel(normalized) ? normalized : void 0;
88
+ } catch {
89
+ return;
90
+ }
91
+ }
92
+ let currentLevel = readEnvLevel() ?? "debug";
93
+ /**
94
+ * Set the runtime log level programmatically. Use this when the deployment can't
95
+ * surface `LOVABLE_MCP_LOG_LEVEL` to the package (e.g. a Cloudflare Worker that
96
+ * passes vars via bindings): call `setLogLevel("debug")` once at server startup.
97
+ */
98
+ function setLogLevel(level) {
99
+ currentLevel = level;
100
+ }
101
+ /** Parse an env value into a LogLevel, or undefined if it names no valid level. */
102
+ function parseLogLevel(raw) {
103
+ const normalized = raw?.trim().toLowerCase();
104
+ return isLogLevel(normalized) ? normalized : void 0;
105
+ }
106
+ /**
107
+ * Apply the log level from an env value: use it when it names a valid level,
108
+ * otherwise fall back to `debug` so the SDK's diagnostics are on by default.
109
+ */
110
+ function applyLogLevelFromEnv(raw) {
111
+ setLogLevel(parseLogLevel(raw) ?? "debug");
112
+ }
113
+ function enabled(level) {
114
+ return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
115
+ }
116
+ function emit(level, method, event, fields) {
117
+ if (!enabled(level)) return;
118
+ const message = `[mcp-js] ${event}`;
119
+ if (fields) console[method](message, fields);
120
+ else console[method](message);
121
+ }
122
+ const log = {
123
+ error: (event, fields) => emit("error", "error", event, fields),
124
+ warn: (event, fields) => emit("warn", "warn", event, fields),
125
+ info: (event, fields) => emit("info", "info", event, fields),
126
+ debug: (event, fields) => emit("debug", "debug", event, fields)
127
+ };
128
+ /** Non-secret error shape for logs: name, message, and a string `code` (jose carries one) when present. */
129
+ function describeError(err) {
130
+ if (err instanceof Error) {
131
+ const code = err.code;
132
+ return {
133
+ name: err.name,
134
+ message: err.message,
135
+ ...typeof code === "string" ? { code } : {}
136
+ };
137
+ }
138
+ return { value: String(err) };
139
+ }
140
+ //#endregion
141
+ Object.defineProperty(exports, "DEFAULT_METRICS_ENDPOINT", {
142
+ enumerable: true,
143
+ get: function() {
144
+ return DEFAULT_METRICS_ENDPOINT;
145
+ }
146
+ });
147
+ Object.defineProperty(exports, "LOG_LEVEL_ENV_VAR", {
148
+ enumerable: true,
149
+ get: function() {
150
+ return LOG_LEVEL_ENV_VAR;
151
+ }
152
+ });
153
+ Object.defineProperty(exports, "applyLogLevelFromEnv", {
154
+ enumerable: true,
155
+ get: function() {
156
+ return applyLogLevelFromEnv;
157
+ }
158
+ });
159
+ Object.defineProperty(exports, "describeError", {
160
+ enumerable: true,
161
+ get: function() {
162
+ return describeError;
163
+ }
164
+ });
165
+ Object.defineProperty(exports, "log", {
166
+ enumerable: true,
167
+ get: function() {
168
+ return log;
169
+ }
170
+ });
171
+ Object.defineProperty(exports, "parseSafeUrl", {
172
+ enumerable: true,
173
+ get: function() {
174
+ return parseSafeUrl;
175
+ }
176
+ });
177
+ Object.defineProperty(exports, "resolveMetricsConfig", {
178
+ enumerable: true,
179
+ get: function() {
180
+ return resolveMetricsConfig;
181
+ }
182
+ });
183
+ Object.defineProperty(exports, "setLogLevel", {
184
+ enumerable: true,
185
+ get: function() {
186
+ return setLogLevel;
187
+ }
188
+ });
189
+ Object.defineProperty(exports, "trimTrailingSlash", {
190
+ enumerable: true,
191
+ get: function() {
192
+ return trimTrailingSlash;
193
+ }
194
+ });
@@ -0,0 +1,123 @@
1
+ import { i as log, r as describeError } from "./logger-2OXtfiIW.js";
2
+ import { t as ToolContext } from "./context-CIpPzN7P.js";
3
+ import { d as nowMs, i as createRequestAuthorizer, n as withCors, t as corsPreflightResponse, u as createNoopRecorder } from "./cors-C2n2LxrC.js";
4
+ import { t as extractTextContent } from "./content-D5LJAHyM.js";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
7
+ //#region src/protocols/mcp/protocol.ts
8
+ /**
9
+ * Adapt a Lovable tool to the SDK's tool callback. The boundary cast bridges
10
+ * our SDK-decoupled content-block types to the SDK's; they match structurally.
11
+ */
12
+ function adaptToolToSdkCallback(tool, auth, recorder) {
13
+ const endUserId = auth?.principal.sub;
14
+ return (async (first) => {
15
+ const args = tool.inputSchema ? first ?? {} : {};
16
+ const start = nowMs();
17
+ let result;
18
+ try {
19
+ result = await tool.handler(args, new ToolContext(auth));
20
+ } catch {
21
+ await recorder.emit({
22
+ tool: tool.name,
23
+ method: "tools/call",
24
+ outcome: "handler_error",
25
+ durationMs: nowMs() - start,
26
+ endUserId
27
+ });
28
+ return {
29
+ content: [{
30
+ type: "text",
31
+ text: "tool execution failed"
32
+ }],
33
+ isError: true
34
+ };
35
+ }
36
+ if (result == null) {
37
+ await recorder.emit({
38
+ tool: tool.name,
39
+ method: "tools/call",
40
+ outcome: "handler_error",
41
+ durationMs: nowMs() - start,
42
+ endUserId
43
+ });
44
+ return {
45
+ content: [{
46
+ type: "text",
47
+ text: `tool "${tool.name}" returned no result`
48
+ }],
49
+ isError: true
50
+ };
51
+ }
52
+ await recorder.emit({
53
+ tool: tool.name,
54
+ method: "tools/call",
55
+ outcome: result.isError ? "tool_error" : "ok",
56
+ durationMs: nowMs() - start,
57
+ errorText: result.isError ? extractTextContent(result.content) : void 0,
58
+ endUserId
59
+ });
60
+ return {
61
+ content: result.content ?? [],
62
+ structuredContent: result.structuredContent,
63
+ isError: result.isError
64
+ };
65
+ });
66
+ }
67
+ /**
68
+ * Build a Web-Standard request handler that serves the MCP protocol over
69
+ * streamable HTTP. A fresh `McpServer` + transport is constructed per
70
+ * request — the transport is stateless, so this is cheap and there is no
71
+ * cross-request state to leak. The per-request `recorder` is supplied by the
72
+ * caller (the stack handler) so telemetry reads the runtime env in-flight.
73
+ */
74
+ function createMcpProtocolHandler(mcp, options = {}) {
75
+ const authorizer = createRequestAuthorizer(mcp, options);
76
+ const handle = async (request, recorder) => {
77
+ const authResult = await authorizer.authorize(request, recorder);
78
+ if (!authResult.ok) return authResult.response;
79
+ try {
80
+ const server = new McpServer({
81
+ name: mcp.name,
82
+ version: mcp.version,
83
+ title: mcp.title
84
+ }, { instructions: mcp.instructions });
85
+ for (const tool of mcp.tools) server.registerTool(tool.name, {
86
+ title: tool.title,
87
+ description: tool.description,
88
+ inputSchema: tool.inputSchema,
89
+ outputSchema: tool.outputSchema,
90
+ annotations: tool.annotations
91
+ }, adaptToolToSdkCallback(tool, authResult.auth, recorder));
92
+ const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
93
+ await server.connect(transport);
94
+ return await transport.handleRequest(request);
95
+ } catch (err) {
96
+ await recorder.emit({
97
+ tool: null,
98
+ method: "transport",
99
+ outcome: "transport_error",
100
+ durationMs: 0,
101
+ endUserId: authResult.auth?.principal.sub
102
+ });
103
+ log.error("mcp.transport_error", {
104
+ ...describeError(err),
105
+ outcome: "500 internal error"
106
+ });
107
+ return Response.json({
108
+ jsonrpc: "2.0",
109
+ id: null,
110
+ error: {
111
+ code: -32603,
112
+ message: "internal error"
113
+ }
114
+ }, { status: 500 });
115
+ }
116
+ };
117
+ return async (request, recorder = createNoopRecorder()) => {
118
+ if (request.method === "OPTIONS") return corsPreflightResponse("GET, POST, DELETE, OPTIONS");
119
+ return withCors(await handle(request, recorder));
120
+ };
121
+ }
122
+ //#endregion
123
+ export { createMcpProtocolHandler as t };
@@ -0,0 +1,128 @@
1
+ const require_logger = require("./logger-BqPOa_E1.cjs");
2
+ const require_context = require("./context-BweeEcoA.cjs");
3
+ const require_cors = require("./cors-Cga2PWEg.cjs");
4
+ const require_content = require("./content-NCYIGgOb.cjs");
5
+ let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
6
+ let _modelcontextprotocol_sdk_server_webStandardStreamableHttp_js = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
7
+ //#region src/protocols/mcp/protocol.ts
8
+ /**
9
+ * Adapt a Lovable tool to the SDK's tool callback. The boundary cast bridges
10
+ * our SDK-decoupled content-block types to the SDK's; they match structurally.
11
+ */
12
+ function adaptToolToSdkCallback(tool, auth, recorder) {
13
+ const endUserId = auth?.principal.sub;
14
+ return (async (first) => {
15
+ const args = tool.inputSchema ? first ?? {} : {};
16
+ const start = require_cors.nowMs();
17
+ let result;
18
+ try {
19
+ result = await tool.handler(args, new require_context.ToolContext(auth));
20
+ } catch {
21
+ await recorder.emit({
22
+ tool: tool.name,
23
+ method: "tools/call",
24
+ outcome: "handler_error",
25
+ durationMs: require_cors.nowMs() - start,
26
+ endUserId
27
+ });
28
+ return {
29
+ content: [{
30
+ type: "text",
31
+ text: "tool execution failed"
32
+ }],
33
+ isError: true
34
+ };
35
+ }
36
+ if (result == null) {
37
+ await recorder.emit({
38
+ tool: tool.name,
39
+ method: "tools/call",
40
+ outcome: "handler_error",
41
+ durationMs: require_cors.nowMs() - start,
42
+ endUserId
43
+ });
44
+ return {
45
+ content: [{
46
+ type: "text",
47
+ text: `tool "${tool.name}" returned no result`
48
+ }],
49
+ isError: true
50
+ };
51
+ }
52
+ await recorder.emit({
53
+ tool: tool.name,
54
+ method: "tools/call",
55
+ outcome: result.isError ? "tool_error" : "ok",
56
+ durationMs: require_cors.nowMs() - start,
57
+ errorText: result.isError ? require_content.extractTextContent(result.content) : void 0,
58
+ endUserId
59
+ });
60
+ return {
61
+ content: result.content ?? [],
62
+ structuredContent: result.structuredContent,
63
+ isError: result.isError
64
+ };
65
+ });
66
+ }
67
+ /**
68
+ * Build a Web-Standard request handler that serves the MCP protocol over
69
+ * streamable HTTP. A fresh `McpServer` + transport is constructed per
70
+ * request — the transport is stateless, so this is cheap and there is no
71
+ * cross-request state to leak. The per-request `recorder` is supplied by the
72
+ * caller (the stack handler) so telemetry reads the runtime env in-flight.
73
+ */
74
+ function createMcpProtocolHandler(mcp, options = {}) {
75
+ const authorizer = require_cors.createRequestAuthorizer(mcp, options);
76
+ const handle = async (request, recorder) => {
77
+ const authResult = await authorizer.authorize(request, recorder);
78
+ if (!authResult.ok) return authResult.response;
79
+ try {
80
+ const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
81
+ name: mcp.name,
82
+ version: mcp.version,
83
+ title: mcp.title
84
+ }, { instructions: mcp.instructions });
85
+ for (const tool of mcp.tools) server.registerTool(tool.name, {
86
+ title: tool.title,
87
+ description: tool.description,
88
+ inputSchema: tool.inputSchema,
89
+ outputSchema: tool.outputSchema,
90
+ annotations: tool.annotations
91
+ }, adaptToolToSdkCallback(tool, authResult.auth, recorder));
92
+ const transport = new _modelcontextprotocol_sdk_server_webStandardStreamableHttp_js.WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
93
+ await server.connect(transport);
94
+ return await transport.handleRequest(request);
95
+ } catch (err) {
96
+ await recorder.emit({
97
+ tool: null,
98
+ method: "transport",
99
+ outcome: "transport_error",
100
+ durationMs: 0,
101
+ endUserId: authResult.auth?.principal.sub
102
+ });
103
+ require_logger.log.error("mcp.transport_error", {
104
+ ...require_logger.describeError(err),
105
+ outcome: "500 internal error"
106
+ });
107
+ return Response.json({
108
+ jsonrpc: "2.0",
109
+ id: null,
110
+ error: {
111
+ code: -32603,
112
+ message: "internal error"
113
+ }
114
+ }, { status: 500 });
115
+ }
116
+ };
117
+ return async (request, recorder = require_cors.createNoopRecorder()) => {
118
+ if (request.method === "OPTIONS") return require_cors.corsPreflightResponse("GET, POST, DELETE, OPTIONS");
119
+ return require_cors.withCors(await handle(request, recorder));
120
+ };
121
+ }
122
+ //#endregion
123
+ Object.defineProperty(exports, "createMcpProtocolHandler", {
124
+ enumerable: true,
125
+ get: function() {
126
+ return createMcpProtocolHandler;
127
+ }
128
+ });
@@ -0,0 +1,12 @@
1
+ //#region src/auth/metadata-path.ts
2
+ /**
3
+ * Default RFC 9728 protected-resource metadata path. Used by the runtime 401
4
+ * challenge (`authorize.ts`, which advertises this URL via the
5
+ * `WWW-Authenticate: resource_metadata` param) and the Vite plugin (which emits
6
+ * the route that serves it) when no `metadataPath` is configured. A configured
7
+ * `metadataPath` overrides it; the plugin injects that same path into every
8
+ * emitted handler, so the advertised URL and the served route still can't drift.
9
+ */
10
+ const OAUTH_PROTECTED_RESOURCE_METADATA_PATH = "/.well-known/oauth-protected-resource";
11
+ //#endregion
12
+ export { OAUTH_PROTECTED_RESOURCE_METADATA_PATH as t };
@@ -0,0 +1,17 @@
1
+ //#region src/auth/metadata-path.ts
2
+ /**
3
+ * Default RFC 9728 protected-resource metadata path. Used by the runtime 401
4
+ * challenge (`authorize.ts`, which advertises this URL via the
5
+ * `WWW-Authenticate: resource_metadata` param) and the Vite plugin (which emits
6
+ * the route that serves it) when no `metadataPath` is configured. A configured
7
+ * `metadataPath` overrides it; the plugin injects that same path into every
8
+ * emitted handler, so the advertised URL and the served route still can't drift.
9
+ */
10
+ const OAUTH_PROTECTED_RESOURCE_METADATA_PATH = "/.well-known/oauth-protected-resource";
11
+ //#endregion
12
+ Object.defineProperty(exports, "OAUTH_PROTECTED_RESOURCE_METADATA_PATH", {
13
+ enumerable: true,
14
+ get: function() {
15
+ return OAUTH_PROTECTED_RESOURCE_METADATA_PATH;
16
+ }
17
+ });
@@ -0,0 +1,9 @@
1
+ //#region package.json
2
+ var version = "0.22.2-rc.1";
3
+ //#endregion
4
+ Object.defineProperty(exports, "version", {
5
+ enumerable: true,
6
+ get: function() {
7
+ return version;
8
+ }
9
+ });
@@ -0,0 +1,4 @@
1
+ //#region package.json
2
+ var version = "0.22.2-rc.1";
3
+ //#endregion
4
+ export { version as t };
@@ -0,0 +1,7 @@
1
+ //#region src/stacks/supabase/paths.ts
2
+ const FUNCTIONS_MOUNT_PREFIX = "/functions/v1/";
3
+ function assertFunctionName(value, label = "functionName") {
4
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) throw new Error(`@lovable.dev/mcp-js: ${label} must be a single path segment matching [A-Za-z0-9_-], got ${JSON.stringify(value)}`);
5
+ }
6
+ //#endregion
7
+ export { assertFunctionName as n, FUNCTIONS_MOUNT_PREFIX as t };
@@ -0,0 +1,18 @@
1
+ //#region src/stacks/supabase/paths.ts
2
+ const FUNCTIONS_MOUNT_PREFIX = "/functions/v1/";
3
+ function assertFunctionName(value, label = "functionName") {
4
+ if (!/^[a-zA-Z0-9_-]+$/.test(value)) throw new Error(`@lovable.dev/mcp-js: ${label} must be a single path segment matching [A-Za-z0-9_-], got ${JSON.stringify(value)}`);
5
+ }
6
+ //#endregion
7
+ Object.defineProperty(exports, "FUNCTIONS_MOUNT_PREFIX", {
8
+ enumerable: true,
9
+ get: function() {
10
+ return FUNCTIONS_MOUNT_PREFIX;
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "assertFunctionName", {
14
+ enumerable: true,
15
+ get: function() {
16
+ return assertFunctionName;
17
+ }
18
+ });