@lovable.dev/mcp-js 0.22.0 → 0.22.1-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.
- package/dist/authorize-CumVyk7p.d.cts +27 -0
- package/dist/authorize-D6p4-9_D.d.ts +27 -0
- package/dist/base-DCe0kP79.d.cts +29 -0
- package/dist/base-DCe0kP79.d.ts +29 -0
- package/dist/cli/extract-manifest.cjs +116 -201
- package/dist/cli/extract-manifest.d.cts +1 -1
- package/dist/cli/extract-manifest.d.ts +1 -1
- package/dist/cli/extract-manifest.js +117 -156
- package/dist/content-D5LJAHyM.js +12 -0
- package/dist/content-NCYIGgOb.cjs +17 -0
- package/dist/context-BweeEcoA.cjs +56 -0
- package/dist/context-CIpPzN7P.js +51 -0
- package/dist/cors-BxwVxCm3.cjs +913 -0
- package/dist/cors-CJRL7tyh.js +830 -0
- package/dist/forwarded--h4efJy-.js +43 -0
- package/dist/forwarded-Pi8Hs5Ps.cjs +48 -0
- package/dist/fs-errors-CWNzOV75.cjs +11 -0
- package/dist/fs-errors-PA2t1TIp.js +6 -0
- package/dist/index.cjs +129 -329
- package/dist/index.d.cts +26 -26
- package/dist/index.d.ts +26 -26
- package/dist/index.js +118 -177
- package/dist/{io-D4srzRKc.d.ts → io-CfSPxeBN.d.ts} +6 -4
- package/dist/io-DPYvBqET.d.cts +15 -0
- package/dist/list-tools-B4TTPEl1.d.cts +8 -0
- package/dist/list-tools-Duj1zT0T.js +46 -0
- package/dist/list-tools-_Hh_o_mD.cjs +57 -0
- package/dist/list-tools-bh6-eqZM.d.ts +8 -0
- package/dist/logger-2OXtfiIW.js +141 -0
- package/dist/logger-BqPOa_E1.cjs +194 -0
- package/dist/mcp--iewDKrV.cjs +128 -0
- package/dist/mcp-CALHyhDi.js +123 -0
- package/dist/metadata-path-CAkNcfyY.js +12 -0
- package/dist/metadata-path-zd7NSNoa.cjs +17 -0
- package/dist/package-CLTXgGyU.cjs +9 -0
- package/dist/package-g7-GHkOW.js +4 -0
- package/dist/paths-IS65L6TA.js +7 -0
- package/dist/paths-OP318a6c.cjs +18 -0
- package/dist/protocols/mcp/index.cjs +3 -750
- package/dist/protocols/mcp/index.d.cts +6 -7
- package/dist/protocols/mcp/index.d.ts +6 -7
- package/dist/protocols/mcp/index.js +2 -12
- package/dist/protocols/oauth-metadata.cjs +48 -539
- package/dist/protocols/oauth-metadata.d.cts +5 -6
- package/dist/protocols/oauth-metadata.d.ts +5 -6
- package/dist/protocols/oauth-metadata.js +52 -10
- package/dist/protocols/rest/index.cjs +5 -843
- package/dist/protocols/rest/index.d.cts +7 -10
- package/dist/protocols/rest/index.d.ts +7 -10
- package/dist/protocols/rest/index.js +3 -16
- package/dist/rest-BcS3SYjx.cjs +122 -0
- package/dist/rest-Dv9Xq9cV.js +117 -0
- package/dist/stacks/supabase/index.cjs +76 -1318
- package/dist/stacks/supabase/index.d.cts +29 -30
- package/dist/stacks/supabase/index.d.ts +29 -30
- package/dist/stacks/supabase/index.js +73 -89
- package/dist/stacks/supabase/vite.cjs +258 -287
- package/dist/stacks/supabase/vite.d.cts +24 -24
- package/dist/stacks/supabase/vite.d.ts +24 -24
- package/dist/stacks/supabase/vite.js +252 -252
- package/dist/stacks/tanstack/index.cjs +42 -1272
- package/dist/stacks/tanstack/index.d.cts +8 -9
- package/dist/stacks/tanstack/index.d.ts +8 -9
- package/dist/stacks/tanstack/index.js +36 -41
- package/dist/stacks/tanstack/vite.cjs +223 -312
- package/dist/stacks/tanstack/vite.d.cts +80 -81
- package/dist/stacks/tanstack/vite.d.ts +80 -81
- package/dist/stacks/tanstack/vite.js +216 -282
- package/dist/types-BYdYYTjk.d.cts +321 -0
- package/dist/types-BYdYYTjk.d.ts +321 -0
- package/package.json +69 -28
- package/dist/authorize-BMeXd_Sh.d.ts +0 -25
- package/dist/base-CM-KCpp6.d.ts +0 -28
- package/dist/chunk-4EHZUUS5.js +0 -141
- package/dist/chunk-6DXGZZA4.js +0 -6
- package/dist/chunk-6KNM7RGD.js +0 -79
- package/dist/chunk-6QFZYYUV.js +0 -11
- package/dist/chunk-EOFPMSND.js +0 -6
- package/dist/chunk-H37EB22A.js +0 -125
- package/dist/chunk-MA5H6PSF.js +0 -46
- package/dist/chunk-P43FIUMZ.js +0 -114
- package/dist/chunk-RK62EMPY.js +0 -741
- package/dist/chunk-RLE4UE63.js +0 -58
- package/dist/chunk-UQK5UO6C.js +0 -26
- package/dist/chunk-XQWJN6DC.js +0 -14
- package/dist/chunk-Y3ZFPEQH.js +0 -8
- 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,128 @@
|
|
|
1
|
+
const require_logger = require("./logger-BqPOa_E1.cjs");
|
|
2
|
+
const require_context = require("./context-BweeEcoA.cjs");
|
|
3
|
+
const require_cors = require("./cors-BxwVxCm3.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,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-CJRL7tyh.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,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,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
|
+
});
|