@lovable.dev/mcp-js 2.1.0-rc.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -82
- package/dist/{authorize-BC4TM__8.d.cts → authorize-CzyL7nmF.d.cts} +1 -1
- package/dist/{authorize-DEsM-zTN.d.ts → authorize-Drz_eJ7O.d.ts} +1 -1
- package/dist/{base-BnlJz6TE.d.ts → base-COwtdWE8.d.ts} +2 -2
- package/dist/{base-4G2k3bMl.d.cts → base-DD4MCXZ6.d.cts} +2 -2
- package/dist/cli/extract-manifest.cjs +1 -1
- package/dist/cli/extract-manifest.js +1 -1
- package/dist/{cors-D4BjUpgU.js → cors-BaRKDl4r.js} +1 -1
- package/dist/{cors-0ZCwmwyK.cjs → cors-D-X0aP4O.cjs} +1 -1
- package/dist/errors-Bwd1L0Rf.js +100 -0
- package/dist/errors-Cr95rSkB.cjs +123 -0
- package/dist/index.cjs +147 -4
- package/dist/index.d.cts +4 -12
- package/dist/index.d.ts +4 -12
- package/dist/index.js +147 -3
- package/dist/{io-BEoJ_gb5.js → io-DG83CLKx.js} +2 -3
- package/dist/{io-Cz81GsrM.cjs → io-DZD6xmJQ.cjs} +2 -3
- package/dist/{io-9jGNgPfl.d.cts → io-Ds5MRSiK.d.cts} +1 -1
- package/dist/{io-BLZ8jYW6.d.ts → io-pl5npWDw.d.ts} +1 -1
- package/dist/{mcp-Q_rjpR99.cjs → mcp-Bx3LUn5O.cjs} +15 -92
- package/dist/{mcp-CuHyVOZK.js → mcp-DcmfehoI.js} +15 -92
- package/dist/{package-BAYb-3dX.js → package-BNFIhH0F.js} +1 -1
- package/dist/{package-DlouusYQ.cjs → package-CFVl3oIe.cjs} +1 -1
- package/dist/protocols/mcp/index.cjs +1 -1
- package/dist/protocols/mcp/index.d.cts +3 -3
- package/dist/protocols/mcp/index.d.ts +3 -3
- package/dist/protocols/mcp/index.js +1 -1
- package/dist/protocols/oauth-metadata.cjs +1 -1
- package/dist/protocols/oauth-metadata.d.cts +3 -3
- package/dist/protocols/oauth-metadata.d.ts +3 -3
- package/dist/protocols/oauth-metadata.js +1 -1
- package/dist/stacks/supabase/index.cjs +2 -2
- package/dist/stacks/supabase/index.d.cts +1 -1
- package/dist/stacks/supabase/index.d.ts +1 -1
- package/dist/stacks/supabase/index.js +2 -2
- package/dist/stacks/supabase/vite.cjs +1 -1
- package/dist/stacks/supabase/vite.d.cts +1 -1
- package/dist/stacks/supabase/vite.d.ts +1 -1
- package/dist/stacks/supabase/vite.js +1 -1
- package/dist/stacks/tanstack/index.cjs +2 -2
- package/dist/stacks/tanstack/index.d.cts +2 -2
- package/dist/stacks/tanstack/index.d.ts +2 -2
- package/dist/stacks/tanstack/index.js +2 -2
- package/dist/stacks/tanstack/vite.d.cts +1 -1
- package/dist/stacks/tanstack/vite.d.ts +1 -1
- package/dist/{types-S6J_QTXw.d.cts → types-B3_lX-L1.d.cts} +25 -60
- package/dist/{types-S6J_QTXw.d.ts → types-B3_lX-L1.d.ts} +25 -60
- package/package.json +2 -2
- package/dist/errors-CdrGi5aP.cjs +0 -309
- package/dist/errors-DTvfh8lb.js +0 -262
package/dist/index.js
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
|
-
import { a as setLogLevel } from "./logger-Ctv5xUSD.js";
|
|
2
|
-
import {
|
|
1
|
+
import { a as setLogLevel, o as parseSafeUrl, s as trimTrailingSlash, u as resolveMetricsConfig } from "./logger-Ctv5xUSD.js";
|
|
2
|
+
import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
|
|
3
|
+
import { i as ToolContext, t as ToolError } from "./errors-Bwd1L0Rf.js";
|
|
4
|
+
//#region src/core/define.ts
|
|
5
|
+
function assertUniqueNames(mcp) {
|
|
6
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7
|
+
for (const tool of mcp.tools) {
|
|
8
|
+
if (seen.has(tool.name)) throw new Error(`@lovable.dev/mcp-js: duplicate tool name "${tool.name}"`);
|
|
9
|
+
seen.add(tool.name);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function assertNonEmptyString(label, value) {
|
|
13
|
+
if (value.trim() === "") throw new Error(`@lovable.dev/mcp-js: ${label} must not be empty`);
|
|
14
|
+
if (value !== value.trim()) throw new Error(`@lovable.dev/mcp-js: ${label} must not have leading or trailing whitespace`);
|
|
15
|
+
}
|
|
16
|
+
function assertHttpsUrlField(name, value) {
|
|
17
|
+
assertNonEmptyString(`auth.${name}`, value);
|
|
18
|
+
parseSafeUrl(`@lovable.dev/mcp-js: auth.${name}`, value);
|
|
19
|
+
}
|
|
20
|
+
function assertScope(scope) {
|
|
21
|
+
if (scope.trim() === "" || /\s/.test(scope)) throw new Error(`@lovable.dev/mcp-js: OAuth scopes must be non-empty space-free tokens`);
|
|
22
|
+
}
|
|
23
|
+
function assertJwtAlgorithm(algorithm) {
|
|
24
|
+
if (algorithm.trim() === "" || /\s/.test(algorithm)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must contain non-empty space-free tokens`);
|
|
25
|
+
if (/^HS\d+$/i.test(algorithm) || algorithm.toLowerCase() === "none") throw new Error(`@lovable.dev/mcp-js: auth.algorithms cannot include "${algorithm}"; this verifier is JWKS-only`);
|
|
26
|
+
}
|
|
27
|
+
const MAX_CLOCK_TOLERANCE_SECONDS = 300;
|
|
28
|
+
function assertClockToleranceSeconds(value) {
|
|
29
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > MAX_CLOCK_TOLERANCE_SECONDS) throw new Error(`@lovable.dev/mcp-js: auth.clockToleranceSeconds must be a non-negative number of seconds no greater than ${MAX_CLOCK_TOLERANCE_SECONDS}`);
|
|
30
|
+
}
|
|
31
|
+
function assertOAuthConfig(auth) {
|
|
32
|
+
if (auth.type !== "oauth") {
|
|
33
|
+
const authType = String(auth.type);
|
|
34
|
+
throw new Error(`@lovable.dev/mcp-js: unsupported auth type "${authType}"`);
|
|
35
|
+
}
|
|
36
|
+
if (auth.issuer === void 0) throw new Error(`@lovable.dev/mcp-js: auth.issuer is required`);
|
|
37
|
+
assertHttpsUrlField("issuer", auth.issuer);
|
|
38
|
+
if (auth.jwksUri !== void 0) assertHttpsUrlField("jwksUri", auth.jwksUri);
|
|
39
|
+
if (auth.resource !== void 0) assertHttpsUrlField("resource", auth.resource);
|
|
40
|
+
if (auth.resourceName !== void 0) assertNonEmptyString("auth.resourceName", auth.resourceName);
|
|
41
|
+
if (auth.resourceDocumentation !== void 0) assertHttpsUrlField("resourceDocumentation", auth.resourceDocumentation);
|
|
42
|
+
if (auth.protectedResourceMetadataUrl !== void 0) assertHttpsUrlField("protectedResourceMetadataUrl", auth.protectedResourceMetadataUrl);
|
|
43
|
+
if (auth.acceptedAudiences !== void 0) {
|
|
44
|
+
if (!Array.isArray(auth.acceptedAudiences)) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must be an array`);
|
|
45
|
+
if (auth.acceptedAudiences.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must not be empty`);
|
|
46
|
+
for (const audience of auth.acceptedAudiences) {
|
|
47
|
+
if (typeof audience !== "string") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences must contain strings`);
|
|
48
|
+
assertNonEmptyString("auth.acceptedAudiences", audience);
|
|
49
|
+
if (trimTrailingSlash(audience) === "") throw new Error(`@lovable.dev/mcp-js: auth.acceptedAudiences entries must not be only slashes`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (auth.requireOAuthClientClaim !== void 0 && typeof auth.requireOAuthClientClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.requireOAuthClientClaim must be a boolean`);
|
|
53
|
+
if (auth.acceptResourceClaim !== void 0 && typeof auth.acceptResourceClaim !== "boolean") throw new Error(`@lovable.dev/mcp-js: auth.acceptResourceClaim must be a boolean`);
|
|
54
|
+
if (auth.requiredScopes !== void 0) {
|
|
55
|
+
if (!Array.isArray(auth.requiredScopes)) throw new Error(`@lovable.dev/mcp-js: auth.requiredScopes must be an array`);
|
|
56
|
+
for (const scope of auth.requiredScopes) assertScope(scope);
|
|
57
|
+
}
|
|
58
|
+
if (auth.algorithms !== void 0) {
|
|
59
|
+
if (!Array.isArray(auth.algorithms)) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must be an array`);
|
|
60
|
+
if (auth.algorithms.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.algorithms must not be empty`);
|
|
61
|
+
for (const algorithm of auth.algorithms) assertJwtAlgorithm(algorithm);
|
|
62
|
+
}
|
|
63
|
+
if (auth.accessTokenTyp !== void 0) {
|
|
64
|
+
if (!Array.isArray(auth.accessTokenTyp)) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must be an array`);
|
|
65
|
+
if (auth.accessTokenTyp.length === 0) throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must not be empty`);
|
|
66
|
+
for (const typ of auth.accessTokenTyp) {
|
|
67
|
+
if (typeof typ !== "string") throw new Error(`@lovable.dev/mcp-js: auth.accessTokenTyp must contain strings`);
|
|
68
|
+
assertNonEmptyString("auth.accessTokenTyp", typ);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (auth.clockToleranceSeconds !== void 0) assertClockToleranceSeconds(auth.clockToleranceSeconds);
|
|
72
|
+
if (auth.resource === void 0 && auth.acceptedAudiences === void 0) throw new Error(`@lovable.dev/mcp-js: auth.resource or auth.acceptedAudiences is required`);
|
|
73
|
+
}
|
|
74
|
+
function freezeAuth(auth) {
|
|
75
|
+
if (!auth) return;
|
|
76
|
+
if (auth.acceptedAudiences) Object.freeze(auth.acceptedAudiences);
|
|
77
|
+
if (auth.requiredScopes) Object.freeze(auth.requiredScopes);
|
|
78
|
+
if (auth.algorithms) Object.freeze(auth.algorithms);
|
|
79
|
+
if (auth.accessTokenTyp) Object.freeze(auth.accessTokenTyp);
|
|
80
|
+
Object.freeze(auth);
|
|
81
|
+
}
|
|
82
|
+
function assertAllowedOrigins(allowedOrigins) {
|
|
83
|
+
if (allowedOrigins === void 0 || allowedOrigins === "any") return;
|
|
84
|
+
if (!Array.isArray(allowedOrigins)) throw new Error(`@lovable.dev/mcp-js: allowedOrigins must be "any" or an array of exact origins`);
|
|
85
|
+
for (const origin of allowedOrigins) {
|
|
86
|
+
if (typeof origin !== "string") throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain strings`);
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = new URL(origin);
|
|
90
|
+
} catch {
|
|
91
|
+
throw new Error(`@lovable.dev/mcp-js: allowedOrigins must contain valid exact origins`);
|
|
92
|
+
}
|
|
93
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.origin !== origin) throw new Error(`@lovable.dev/mcp-js: allowedOrigins entry "${origin}" must be an exact http(s) origin without a path, query, fragment, or trailing slash`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function assertToolSchemas(mcp) {
|
|
97
|
+
for (const tool of mcp.tools) for (const [name, definition, strategy] of [[
|
|
98
|
+
"inputSchema",
|
|
99
|
+
tool.inputSchema,
|
|
100
|
+
"input"
|
|
101
|
+
], [
|
|
102
|
+
"outputSchema",
|
|
103
|
+
tool.outputSchema,
|
|
104
|
+
"output"
|
|
105
|
+
]]) {
|
|
106
|
+
if (!definition) continue;
|
|
107
|
+
try {
|
|
108
|
+
jsonSchemaFromDefinition(definition, strategy);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
111
|
+
throw new Error(`@lovable.dev/mcp-js: tool "${tool.name}" ${name} cannot be represented as JSON Schema${detail}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Declare a single MCP tool. Import the result into your MCP definition's
|
|
117
|
+
* `tools` array — `defineMcp({ tools: [echoTool, ...] })`.
|
|
118
|
+
*
|
|
119
|
+
* `inputSchema` is a raw zod shape (e.g. `{ text: z.string() }`), not a
|
|
120
|
+
* full `z.object(...)` — the MCP SDK builds the object wrapper internally
|
|
121
|
+
* and the raw shape is what the JSON-RPC `tools/list` payload exposes.
|
|
122
|
+
*/
|
|
123
|
+
function defineTool(def) {
|
|
124
|
+
return def;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Declare the MCP server. `export default` the result from your MCP
|
|
128
|
+
* entrypoint (default `lib/mcp/index.ts`); the Vite plugin reads it to
|
|
129
|
+
* emit the framework-specific route(s) at build time.
|
|
130
|
+
*/
|
|
131
|
+
function defineMcp(def) {
|
|
132
|
+
assertNonEmptyString("name", def.name);
|
|
133
|
+
assertNonEmptyString("title", def.title);
|
|
134
|
+
assertNonEmptyString("version", def.version);
|
|
135
|
+
assertUniqueNames(def);
|
|
136
|
+
if (def.auth) assertOAuthConfig(def.auth);
|
|
137
|
+
assertAllowedOrigins(def.allowedOrigins);
|
|
138
|
+
assertToolSchemas(def);
|
|
139
|
+
resolveMetricsConfig(def.metrics);
|
|
140
|
+
freezeAuth(def.auth);
|
|
141
|
+
if (Array.isArray(def.allowedOrigins)) Object.freeze(def.allowedOrigins);
|
|
142
|
+
Object.freeze(def.tools);
|
|
143
|
+
for (const tool of def.tools) Object.freeze(tool);
|
|
144
|
+
return def;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
3
147
|
//#region src/auth/config.ts
|
|
4
148
|
function frozenArray(value) {
|
|
5
149
|
return value === void 0 ? void 0 : Object.freeze([...value]);
|
|
@@ -34,4 +178,4 @@ function issuer(options) {
|
|
|
34
178
|
const oauth = Object.freeze({ issuer });
|
|
35
179
|
const auth = Object.freeze({ oauth });
|
|
36
180
|
//#endregion
|
|
37
|
-
export {
|
|
181
|
+
export { ToolContext, ToolError, auth, defineMcp, defineTool, setLogLevel };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
|
|
2
|
-
import { t as version } from "./package-
|
|
2
|
+
import { t as version } from "./package-BNFIhH0F.js";
|
|
3
3
|
import { t as isFileMissing } from "./fs-errors-PA2t1TIp.js";
|
|
4
4
|
import { lstatSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
@@ -23,8 +23,7 @@ function buildMcpListing(mcp) {
|
|
|
23
23
|
description: tool.description,
|
|
24
24
|
annotations: tool.annotations,
|
|
25
25
|
inputSchema: schemaToJsonSchema(tool.inputSchema, "input"),
|
|
26
|
-
outputSchema: schemaToJsonSchema(tool.outputSchema, "output")
|
|
27
|
-
...tool.enabled ? { conditional: true } : {}
|
|
26
|
+
outputSchema: schemaToJsonSchema(tool.outputSchema, "output")
|
|
28
27
|
}))
|
|
29
28
|
};
|
|
30
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_schema = require("./schema-D3vClxb7.cjs");
|
|
2
|
-
const require_package = require("./package-
|
|
2
|
+
const require_package = require("./package-CFVl3oIe.cjs");
|
|
3
3
|
const require_fs_errors = require("./fs-errors-CWNzOV75.cjs");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
let node_path = require("node:path");
|
|
@@ -23,8 +23,7 @@ function buildMcpListing(mcp) {
|
|
|
23
23
|
description: tool.description,
|
|
24
24
|
annotations: tool.annotations,
|
|
25
25
|
inputSchema: schemaToJsonSchema(tool.inputSchema, "input"),
|
|
26
|
-
outputSchema: schemaToJsonSchema(tool.outputSchema, "output")
|
|
27
|
-
...tool.enabled ? { conditional: true } : {}
|
|
26
|
+
outputSchema: schemaToJsonSchema(tool.outputSchema, "output")
|
|
28
27
|
}))
|
|
29
28
|
};
|
|
30
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const require_logger = require("./logger-CN1q-KNn.cjs");
|
|
2
2
|
const require_schema = require("./schema-D3vClxb7.cjs");
|
|
3
|
-
const require_errors = require("./errors-
|
|
4
|
-
const require_cors = require("./cors-
|
|
3
|
+
const require_errors = require("./errors-Cr95rSkB.cjs");
|
|
4
|
+
const require_cors = require("./cors-D-X0aP4O.cjs");
|
|
5
5
|
let _modelcontextprotocol_sdk_server_zod_compat_js = require("@modelcontextprotocol/sdk/server/zod-compat.js");
|
|
6
6
|
let _modelcontextprotocol_server = require("@modelcontextprotocol/server");
|
|
7
7
|
//#region src/core/content.ts
|
|
@@ -117,52 +117,6 @@ function createGatedHandler(gate) {
|
|
|
117
117
|
//#endregion
|
|
118
118
|
//#region src/protocols/mcp/protocol.ts
|
|
119
119
|
const MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
120
|
-
const HOUR_MS = 3600 * 1e3;
|
|
121
|
-
const NO_OPERATIONS = {
|
|
122
|
-
listTools: false,
|
|
123
|
-
calledTools: /* @__PURE__ */ new Set()
|
|
124
|
-
};
|
|
125
|
-
function collectRequestOperations(value, calledTools) {
|
|
126
|
-
if (Array.isArray(value)) {
|
|
127
|
-
let listTools = false;
|
|
128
|
-
for (const item of value) listTools = collectRequestOperations(item, calledTools) || listTools;
|
|
129
|
-
return listTools;
|
|
130
|
-
}
|
|
131
|
-
if (!isPlainObject(value)) return false;
|
|
132
|
-
if (value.method === "tools/list") return true;
|
|
133
|
-
if (value.method === "tools/call" && isPlainObject(value.params) && typeof value.params.name === "string") calledTools.add(value.params.name);
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
/** Marks a failure in app-owned `createAppContext` or `enabled` code so telemetry
|
|
137
|
-
* can attribute it to the author rather than to the transport. */
|
|
138
|
-
var AppContextError = class extends Error {
|
|
139
|
-
constructor(cause) {
|
|
140
|
-
super("app context evaluation failed", { cause });
|
|
141
|
-
this.name = "AppContextError";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
async function withAppContextError(run) {
|
|
145
|
-
try {
|
|
146
|
-
return await run();
|
|
147
|
-
} catch (cause) {
|
|
148
|
-
throw new AppContextError(cause);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
async function classifyRequest(request) {
|
|
152
|
-
try {
|
|
153
|
-
const parsedBody = await request.clone().json();
|
|
154
|
-
const calledTools = /* @__PURE__ */ new Set();
|
|
155
|
-
return {
|
|
156
|
-
operations: {
|
|
157
|
-
listTools: collectRequestOperations(parsedBody, calledTools),
|
|
158
|
-
calledTools
|
|
159
|
-
},
|
|
160
|
-
parsedBody
|
|
161
|
-
};
|
|
162
|
-
} catch {
|
|
163
|
-
return { operations: NO_OPERATIONS };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
120
|
function statelessMethodNotAllowed(allow) {
|
|
167
121
|
return Response.json({
|
|
168
122
|
jsonrpc: "2.0",
|
|
@@ -237,12 +191,12 @@ function toolRequestContext(sdkCtx, protocol) {
|
|
|
237
191
|
sendProgress
|
|
238
192
|
};
|
|
239
193
|
}
|
|
240
|
-
async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx
|
|
194
|
+
async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
|
|
241
195
|
const endUserId = auth?.principal.sub;
|
|
242
196
|
const start = require_cors.nowMs();
|
|
243
197
|
let result;
|
|
244
198
|
try {
|
|
245
|
-
result = await tool.handler(args, new require_errors.ToolContext(auth, toolRequestContext(sdkCtx, protocol)
|
|
199
|
+
result = await tool.handler(args, new require_errors.ToolContext(auth, toolRequestContext(sdkCtx, protocol)));
|
|
246
200
|
} catch (err) {
|
|
247
201
|
const callerMessage = require_errors.resolveToolErrorMessage(err);
|
|
248
202
|
if (callerMessage === void 0) {
|
|
@@ -300,10 +254,10 @@ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx, appConte
|
|
|
300
254
|
});
|
|
301
255
|
return result;
|
|
302
256
|
}
|
|
303
|
-
function adaptToolCallback(tool, auth, recorder, protocol
|
|
257
|
+
function adaptToolCallback(tool, auth, recorder, protocol) {
|
|
304
258
|
return async (first, second) => {
|
|
305
259
|
const sdkCtx = tool.inputSchema ? second : first;
|
|
306
|
-
const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx
|
|
260
|
+
const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx);
|
|
307
261
|
return {
|
|
308
262
|
content: result.content ?? [],
|
|
309
263
|
structuredContent: result.structuredContent,
|
|
@@ -311,52 +265,23 @@ function adaptToolCallback(tool, auth, recorder, protocol, appContext) {
|
|
|
311
265
|
};
|
|
312
266
|
};
|
|
313
267
|
}
|
|
314
|
-
|
|
315
|
-
const calledTools = operations ? mcp.tools.filter((tool) => operations.calledTools.has(tool.name)) : mcp.tools;
|
|
316
|
-
const selectedTools = !operations || operations.listTools ? mcp.tools : calledTools;
|
|
317
|
-
const hasConditionalTools = mcp.tools.some((tool) => tool.enabled !== void 0);
|
|
318
|
-
const needsAppContext = operations?.listTools === true && hasConditionalTools || calledTools.some((tool) => tool.enabled !== void 0 || require_errors.toolRequiresAppContext(tool));
|
|
319
|
-
const { createAppContext } = mcp;
|
|
320
|
-
const appContext = needsAppContext && createAppContext ? await withAppContextError(() => createAppContext({
|
|
321
|
-
auth: new require_errors.AuthContext(auth),
|
|
322
|
-
signal
|
|
323
|
-
})) : void 0;
|
|
324
|
-
const visibilityContext = Object.freeze({ appContext });
|
|
325
|
-
const cacheHint = hasConditionalTools ? {
|
|
326
|
-
cacheScope: "private",
|
|
327
|
-
ttlMs: 12 * HOUR_MS
|
|
328
|
-
} : {
|
|
329
|
-
cacheScope: "public",
|
|
330
|
-
ttlMs: 24 * HOUR_MS
|
|
331
|
-
};
|
|
268
|
+
function buildServer(mcp, auth, recorder, era) {
|
|
332
269
|
const server = new _modelcontextprotocol_server.McpServer({
|
|
333
270
|
name: mcp.name,
|
|
334
271
|
version: mcp.version,
|
|
335
272
|
title: mcp.title
|
|
336
273
|
}, {
|
|
337
274
|
instructions: mcp.instructions,
|
|
338
|
-
capabilities: { tools: { listChanged: false } }
|
|
339
|
-
cacheHints: {
|
|
340
|
-
"tools/list": cacheHint,
|
|
341
|
-
"server/discover": cacheHint
|
|
342
|
-
}
|
|
275
|
+
capabilities: { tools: { listChanged: false } }
|
|
343
276
|
});
|
|
344
|
-
for (const tool of
|
|
345
|
-
if (tool.enabled) {
|
|
346
|
-
const { enabled } = tool;
|
|
347
|
-
if (!await withAppContextError(() => {
|
|
348
|
-
const value = enabled(visibilityContext);
|
|
349
|
-
if (typeof value !== "boolean") throw new TypeError(`@lovable.dev/mcp-js: tool "${tool.name}" enabled must return a boolean synchronously`);
|
|
350
|
-
return value;
|
|
351
|
-
})) continue;
|
|
352
|
-
}
|
|
277
|
+
for (const tool of mcp.tools) {
|
|
353
278
|
const config = {
|
|
354
279
|
title: tool.title,
|
|
355
280
|
description: tool.description,
|
|
356
281
|
annotations: tool.annotations,
|
|
357
282
|
...tool.outputSchema ? { outputSchema: standardSchemaFromDefinition(tool.outputSchema) } : {}
|
|
358
283
|
};
|
|
359
|
-
const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION
|
|
284
|
+
const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION);
|
|
360
285
|
if (tool.inputSchema) server.registerTool(tool.name, {
|
|
361
286
|
...config,
|
|
362
287
|
inputSchema: standardSchemaFromDefinition(tool.inputSchema)
|
|
@@ -377,28 +302,26 @@ function createMcpProtocolHandler(mcp, options = {}) {
|
|
|
377
302
|
const handle = async (request, authResult, recorder) => {
|
|
378
303
|
let protocolError;
|
|
379
304
|
const reportTransportError = async (error) => {
|
|
380
|
-
const appContextFailure = error instanceof AppContextError;
|
|
381
305
|
await recorder.emit({
|
|
382
306
|
tool: null,
|
|
383
307
|
method: "transport",
|
|
384
|
-
outcome:
|
|
308
|
+
outcome: "transport_error",
|
|
385
309
|
durationMs: 0,
|
|
386
310
|
endUserId: authResult.auth?.principal.sub
|
|
387
311
|
});
|
|
388
|
-
require_logger.log.error(
|
|
389
|
-
...error === void 0 ? {} : require_logger.describeError(
|
|
312
|
+
require_logger.log.error("mcp.transport_error", {
|
|
313
|
+
...error === void 0 ? {} : require_logger.describeError(error),
|
|
390
314
|
outcome: "500 internal error"
|
|
391
315
|
});
|
|
392
316
|
};
|
|
393
317
|
try {
|
|
394
|
-
const
|
|
395
|
-
const response = await (0, _modelcontextprotocol_server.createMcpHandler)(({ era, requestInfo }) => buildServer(mcp, authResult.auth, recorder, era, requestInfo?.signal ?? request.signal, classified?.operations), {
|
|
318
|
+
const response = await (0, _modelcontextprotocol_server.createMcpHandler)(({ era }) => buildServer(mcp, authResult.auth, recorder, era), {
|
|
396
319
|
legacy: "stateless",
|
|
397
320
|
maxSubscriptions: 0,
|
|
398
321
|
onerror: (error) => {
|
|
399
322
|
protocolError = error;
|
|
400
323
|
}
|
|
401
|
-
}).fetch(request
|
|
324
|
+
}).fetch(request);
|
|
402
325
|
if (response.status >= 500) await reportTransportError(protocolError);
|
|
403
326
|
return response;
|
|
404
327
|
} catch (err) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as log, r as describeError } from "./logger-Ctv5xUSD.js";
|
|
2
2
|
import { n as schemaFromDefinition, t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
|
|
3
|
-
import {
|
|
4
|
-
import { d as nowMs, i as normalizeHttpMethod, l as emitBeforeResponse, n as createRequestAuthorizer, p as finalizeWireResponse, t as evaluateCors, u as createNoopRecorder } from "./cors-
|
|
3
|
+
import { i as ToolContext, n as errorSummary, r as resolveToolErrorMessage } from "./errors-Bwd1L0Rf.js";
|
|
4
|
+
import { d as nowMs, i as normalizeHttpMethod, l as emitBeforeResponse, n as createRequestAuthorizer, p as finalizeWireResponse, t as evaluateCors, u as createNoopRecorder } from "./cors-BaRKDl4r.js";
|
|
5
5
|
import { getParseErrorMessage, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
6
6
|
import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, McpServer, createMcpHandler } from "@modelcontextprotocol/server";
|
|
7
7
|
//#region src/core/content.ts
|
|
@@ -117,52 +117,6 @@ function createGatedHandler(gate) {
|
|
|
117
117
|
//#endregion
|
|
118
118
|
//#region src/protocols/mcp/protocol.ts
|
|
119
119
|
const MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
120
|
-
const HOUR_MS = 3600 * 1e3;
|
|
121
|
-
const NO_OPERATIONS = {
|
|
122
|
-
listTools: false,
|
|
123
|
-
calledTools: /* @__PURE__ */ new Set()
|
|
124
|
-
};
|
|
125
|
-
function collectRequestOperations(value, calledTools) {
|
|
126
|
-
if (Array.isArray(value)) {
|
|
127
|
-
let listTools = false;
|
|
128
|
-
for (const item of value) listTools = collectRequestOperations(item, calledTools) || listTools;
|
|
129
|
-
return listTools;
|
|
130
|
-
}
|
|
131
|
-
if (!isPlainObject(value)) return false;
|
|
132
|
-
if (value.method === "tools/list") return true;
|
|
133
|
-
if (value.method === "tools/call" && isPlainObject(value.params) && typeof value.params.name === "string") calledTools.add(value.params.name);
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
/** Marks a failure in app-owned `createAppContext` or `enabled` code so telemetry
|
|
137
|
-
* can attribute it to the author rather than to the transport. */
|
|
138
|
-
var AppContextError = class extends Error {
|
|
139
|
-
constructor(cause) {
|
|
140
|
-
super("app context evaluation failed", { cause });
|
|
141
|
-
this.name = "AppContextError";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
async function withAppContextError(run) {
|
|
145
|
-
try {
|
|
146
|
-
return await run();
|
|
147
|
-
} catch (cause) {
|
|
148
|
-
throw new AppContextError(cause);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
async function classifyRequest(request) {
|
|
152
|
-
try {
|
|
153
|
-
const parsedBody = await request.clone().json();
|
|
154
|
-
const calledTools = /* @__PURE__ */ new Set();
|
|
155
|
-
return {
|
|
156
|
-
operations: {
|
|
157
|
-
listTools: collectRequestOperations(parsedBody, calledTools),
|
|
158
|
-
calledTools
|
|
159
|
-
},
|
|
160
|
-
parsedBody
|
|
161
|
-
};
|
|
162
|
-
} catch {
|
|
163
|
-
return { operations: NO_OPERATIONS };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
120
|
function statelessMethodNotAllowed(allow) {
|
|
167
121
|
return Response.json({
|
|
168
122
|
jsonrpc: "2.0",
|
|
@@ -237,12 +191,12 @@ function toolRequestContext(sdkCtx, protocol) {
|
|
|
237
191
|
sendProgress
|
|
238
192
|
};
|
|
239
193
|
}
|
|
240
|
-
async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx
|
|
194
|
+
async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
|
|
241
195
|
const endUserId = auth?.principal.sub;
|
|
242
196
|
const start = nowMs();
|
|
243
197
|
let result;
|
|
244
198
|
try {
|
|
245
|
-
result = await tool.handler(args, new ToolContext(auth, toolRequestContext(sdkCtx, protocol)
|
|
199
|
+
result = await tool.handler(args, new ToolContext(auth, toolRequestContext(sdkCtx, protocol)));
|
|
246
200
|
} catch (err) {
|
|
247
201
|
const callerMessage = resolveToolErrorMessage(err);
|
|
248
202
|
if (callerMessage === void 0) {
|
|
@@ -300,10 +254,10 @@ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx, appConte
|
|
|
300
254
|
});
|
|
301
255
|
return result;
|
|
302
256
|
}
|
|
303
|
-
function adaptToolCallback(tool, auth, recorder, protocol
|
|
257
|
+
function adaptToolCallback(tool, auth, recorder, protocol) {
|
|
304
258
|
return async (first, second) => {
|
|
305
259
|
const sdkCtx = tool.inputSchema ? second : first;
|
|
306
|
-
const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx
|
|
260
|
+
const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx);
|
|
307
261
|
return {
|
|
308
262
|
content: result.content ?? [],
|
|
309
263
|
structuredContent: result.structuredContent,
|
|
@@ -311,52 +265,23 @@ function adaptToolCallback(tool, auth, recorder, protocol, appContext) {
|
|
|
311
265
|
};
|
|
312
266
|
};
|
|
313
267
|
}
|
|
314
|
-
|
|
315
|
-
const calledTools = operations ? mcp.tools.filter((tool) => operations.calledTools.has(tool.name)) : mcp.tools;
|
|
316
|
-
const selectedTools = !operations || operations.listTools ? mcp.tools : calledTools;
|
|
317
|
-
const hasConditionalTools = mcp.tools.some((tool) => tool.enabled !== void 0);
|
|
318
|
-
const needsAppContext = operations?.listTools === true && hasConditionalTools || calledTools.some((tool) => tool.enabled !== void 0 || toolRequiresAppContext(tool));
|
|
319
|
-
const { createAppContext } = mcp;
|
|
320
|
-
const appContext = needsAppContext && createAppContext ? await withAppContextError(() => createAppContext({
|
|
321
|
-
auth: new AuthContext(auth),
|
|
322
|
-
signal
|
|
323
|
-
})) : void 0;
|
|
324
|
-
const visibilityContext = Object.freeze({ appContext });
|
|
325
|
-
const cacheHint = hasConditionalTools ? {
|
|
326
|
-
cacheScope: "private",
|
|
327
|
-
ttlMs: 12 * HOUR_MS
|
|
328
|
-
} : {
|
|
329
|
-
cacheScope: "public",
|
|
330
|
-
ttlMs: 24 * HOUR_MS
|
|
331
|
-
};
|
|
268
|
+
function buildServer(mcp, auth, recorder, era) {
|
|
332
269
|
const server = new McpServer({
|
|
333
270
|
name: mcp.name,
|
|
334
271
|
version: mcp.version,
|
|
335
272
|
title: mcp.title
|
|
336
273
|
}, {
|
|
337
274
|
instructions: mcp.instructions,
|
|
338
|
-
capabilities: { tools: { listChanged: false } }
|
|
339
|
-
cacheHints: {
|
|
340
|
-
"tools/list": cacheHint,
|
|
341
|
-
"server/discover": cacheHint
|
|
342
|
-
}
|
|
275
|
+
capabilities: { tools: { listChanged: false } }
|
|
343
276
|
});
|
|
344
|
-
for (const tool of
|
|
345
|
-
if (tool.enabled) {
|
|
346
|
-
const { enabled } = tool;
|
|
347
|
-
if (!await withAppContextError(() => {
|
|
348
|
-
const value = enabled(visibilityContext);
|
|
349
|
-
if (typeof value !== "boolean") throw new TypeError(`@lovable.dev/mcp-js: tool "${tool.name}" enabled must return a boolean synchronously`);
|
|
350
|
-
return value;
|
|
351
|
-
})) continue;
|
|
352
|
-
}
|
|
277
|
+
for (const tool of mcp.tools) {
|
|
353
278
|
const config = {
|
|
354
279
|
title: tool.title,
|
|
355
280
|
description: tool.description,
|
|
356
281
|
annotations: tool.annotations,
|
|
357
282
|
...tool.outputSchema ? { outputSchema: standardSchemaFromDefinition(tool.outputSchema) } : {}
|
|
358
283
|
};
|
|
359
|
-
const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION
|
|
284
|
+
const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION);
|
|
360
285
|
if (tool.inputSchema) server.registerTool(tool.name, {
|
|
361
286
|
...config,
|
|
362
287
|
inputSchema: standardSchemaFromDefinition(tool.inputSchema)
|
|
@@ -377,28 +302,26 @@ function createMcpProtocolHandler(mcp, options = {}) {
|
|
|
377
302
|
const handle = async (request, authResult, recorder) => {
|
|
378
303
|
let protocolError;
|
|
379
304
|
const reportTransportError = async (error) => {
|
|
380
|
-
const appContextFailure = error instanceof AppContextError;
|
|
381
305
|
await recorder.emit({
|
|
382
306
|
tool: null,
|
|
383
307
|
method: "transport",
|
|
384
|
-
outcome:
|
|
308
|
+
outcome: "transport_error",
|
|
385
309
|
durationMs: 0,
|
|
386
310
|
endUserId: authResult.auth?.principal.sub
|
|
387
311
|
});
|
|
388
|
-
log.error(
|
|
389
|
-
...error === void 0 ? {} : describeError(
|
|
312
|
+
log.error("mcp.transport_error", {
|
|
313
|
+
...error === void 0 ? {} : describeError(error),
|
|
390
314
|
outcome: "500 internal error"
|
|
391
315
|
});
|
|
392
316
|
};
|
|
393
317
|
try {
|
|
394
|
-
const
|
|
395
|
-
const response = await createMcpHandler(({ era, requestInfo }) => buildServer(mcp, authResult.auth, recorder, era, requestInfo?.signal ?? request.signal, classified?.operations), {
|
|
318
|
+
const response = await createMcpHandler(({ era }) => buildServer(mcp, authResult.auth, recorder, era), {
|
|
396
319
|
legacy: "stateless",
|
|
397
320
|
maxSubscriptions: 0,
|
|
398
321
|
onerror: (error) => {
|
|
399
322
|
protocolError = error;
|
|
400
323
|
}
|
|
401
|
-
}).fetch(request
|
|
324
|
+
}).fetch(request);
|
|
402
325
|
if (response.status >= 500) await reportTransportError(protocolError);
|
|
403
326
|
return response;
|
|
404
327
|
} catch (err) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as MetricsRecorder } from "../../base-
|
|
3
|
-
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-
|
|
1
|
+
import { d as McpDefinition } from "../../types-B3_lX-L1.cjs";
|
|
2
|
+
import { t as MetricsRecorder } from "../../base-DD4MCXZ6.cjs";
|
|
3
|
+
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-CzyL7nmF.cjs";
|
|
4
4
|
//#region src/protocols/mcp/protocol.d.ts
|
|
5
5
|
type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder, scheduleBackground?: ScheduleBackground) => Promise<Response>;
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as MetricsRecorder } from "../../base-
|
|
3
|
-
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-
|
|
1
|
+
import { d as McpDefinition } from "../../types-B3_lX-L1.js";
|
|
2
|
+
import { t as MetricsRecorder } from "../../base-COwtdWE8.js";
|
|
3
|
+
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-Drz_eJ7O.js";
|
|
4
4
|
//#region src/protocols/mcp/protocol.d.ts
|
|
5
5
|
type McpProtocolHandler = (request: Request, recorder?: MetricsRecorder, scheduleBackground?: ScheduleBackground) => Promise<Response>;
|
|
6
6
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createMcpProtocolHandler } from "../../mcp-
|
|
1
|
+
import { t as createMcpProtocolHandler } from "../../mcp-DcmfehoI.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-
|
|
3
|
+
const require_cors = require("../cors-D-X0aP4O.cjs");
|
|
4
4
|
//#region src/protocols/oauth-metadata.ts
|
|
5
5
|
function notFound() {
|
|
6
6
|
return new Response(JSON.stringify({ error: "not found" }), {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as MetricsRecorder } from "../base-
|
|
3
|
-
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-
|
|
1
|
+
import { d as McpDefinition } from "../types-B3_lX-L1.cjs";
|
|
2
|
+
import { t as MetricsRecorder } from "../base-DD4MCXZ6.cjs";
|
|
3
|
+
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-CzyL7nmF.cjs";
|
|
4
4
|
//#region src/protocols/oauth-metadata.d.ts
|
|
5
5
|
type OAuthProtectedResourceMetadataHandler = (request: Request, recorder?: MetricsRecorder, scheduleBackground?: ScheduleBackground) => Promise<Response>;
|
|
6
6
|
declare function createOAuthProtectedResourceMetadataHandler(mcp: McpDefinition, options?: McpRuntimeOptions): OAuthProtectedResourceMetadataHandler;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as MetricsRecorder } from "../base-
|
|
3
|
-
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-
|
|
1
|
+
import { d as McpDefinition } from "../types-B3_lX-L1.js";
|
|
2
|
+
import { t as MetricsRecorder } from "../base-COwtdWE8.js";
|
|
3
|
+
import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-Drz_eJ7O.js";
|
|
4
4
|
//#region src/protocols/oauth-metadata.d.ts
|
|
5
5
|
type OAuthProtectedResourceMetadataHandler = (request: Request, recorder?: MetricsRecorder, scheduleBackground?: ScheduleBackground) => Promise<Response>;
|
|
6
6
|
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, f as JSON_HEADERS, i as normalizeHttpMethod, l as emitBeforeResponse, m as methodNotAllowed, p as finalizeWireResponse, r as getOAuthRuntime, s as resolveProtectedResource, t as evaluateCors, u as createNoopRecorder } from "../cors-
|
|
2
|
+
import { a as oauthConfigurationErrorResponse, f as JSON_HEADERS, i as normalizeHttpMethod, l as emitBeforeResponse, m as methodNotAllowed, p as finalizeWireResponse, r as getOAuthRuntime, s as resolveProtectedResource, t as evaluateCors, u as createNoopRecorder } from "../cors-BaRKDl4r.js";
|
|
3
3
|
//#region src/protocols/oauth-metadata.ts
|
|
4
4
|
function notFound() {
|
|
5
5
|
return new Response(JSON.stringify({ error: "not found" }), {
|