@lovable.dev/mcp-js 2.0.4-rc.0 → 2.1.0-rc.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.
Files changed (50) hide show
  1. package/README.md +82 -1
  2. package/dist/{authorize-oCEahmRv.d.cts → authorize-BC4TM__8.d.cts} +1 -1
  3. package/dist/{authorize-B5VMSzcN.d.ts → authorize-DEsM-zTN.d.ts} +1 -1
  4. package/dist/{base-DnCoJOZN.d.ts → base-4G2k3bMl.d.cts} +2 -2
  5. package/dist/{base-DAkOPRay.d.cts → base-BnlJz6TE.d.ts} +2 -2
  6. package/dist/cli/extract-manifest.cjs +1 -1
  7. package/dist/cli/extract-manifest.js +1 -1
  8. package/dist/{cors-DheH0sX2.cjs → cors-0ZCwmwyK.cjs} +1 -1
  9. package/dist/{cors-K-QaLAV0.js → cors-D4BjUpgU.js} +1 -1
  10. package/dist/errors-CdrGi5aP.cjs +309 -0
  11. package/dist/errors-DTvfh8lb.js +262 -0
  12. package/dist/index.cjs +4 -147
  13. package/dist/index.d.cts +12 -4
  14. package/dist/index.d.ts +12 -4
  15. package/dist/index.js +3 -147
  16. package/dist/{io-D2PGAhYM.d.cts → io-9jGNgPfl.d.cts} +1 -1
  17. package/dist/{io-CanMDPsW.js → io-BEoJ_gb5.js} +3 -2
  18. package/dist/{io-BD2TuqtG.d.ts → io-BLZ8jYW6.d.ts} +1 -1
  19. package/dist/{io-B5Mit9aD.cjs → io-Cz81GsrM.cjs} +3 -2
  20. package/dist/{mcp-TJZHxHwb.js → mcp-CuHyVOZK.js} +92 -15
  21. package/dist/{mcp-CY55D6Km.cjs → mcp-Q_rjpR99.cjs} +92 -15
  22. package/dist/{package-ZzwBAUf7.js → package-BAYb-3dX.js} +1 -1
  23. package/dist/{package-ClsLrfmB.cjs → package-DlouusYQ.cjs} +1 -1
  24. package/dist/protocols/mcp/index.cjs +1 -1
  25. package/dist/protocols/mcp/index.d.cts +3 -3
  26. package/dist/protocols/mcp/index.d.ts +3 -3
  27. package/dist/protocols/mcp/index.js +1 -1
  28. package/dist/protocols/oauth-metadata.cjs +1 -1
  29. package/dist/protocols/oauth-metadata.d.cts +3 -3
  30. package/dist/protocols/oauth-metadata.d.ts +3 -3
  31. package/dist/protocols/oauth-metadata.js +1 -1
  32. package/dist/stacks/supabase/index.cjs +2 -2
  33. package/dist/stacks/supabase/index.d.cts +1 -1
  34. package/dist/stacks/supabase/index.d.ts +1 -1
  35. package/dist/stacks/supabase/index.js +2 -2
  36. package/dist/stacks/supabase/vite.cjs +1 -1
  37. package/dist/stacks/supabase/vite.d.cts +1 -1
  38. package/dist/stacks/supabase/vite.d.ts +1 -1
  39. package/dist/stacks/supabase/vite.js +1 -1
  40. package/dist/stacks/tanstack/index.cjs +2 -2
  41. package/dist/stacks/tanstack/index.d.cts +2 -2
  42. package/dist/stacks/tanstack/index.d.ts +2 -2
  43. package/dist/stacks/tanstack/index.js +2 -2
  44. package/dist/stacks/tanstack/vite.d.cts +1 -1
  45. package/dist/stacks/tanstack/vite.d.ts +1 -1
  46. package/dist/{types-C6O4ciic.d.ts → types-S6J_QTXw.d.cts} +60 -20
  47. package/dist/{types-C6O4ciic.d.cts → types-S6J_QTXw.d.ts} +60 -20
  48. package/package.json +1 -1
  49. package/dist/errors-Bwd1L0Rf.js +0 -100
  50. package/dist/errors-Cr95rSkB.cjs +0 -123
package/dist/index.js CHANGED
@@ -1,149 +1,5 @@
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
1
+ import { a as setLogLevel } from "./logger-Ctv5xUSD.js";
2
+ import { a as ToolContext, i as AuthContext, o as defineMcp, s as defineTool, t as ToolError } from "./errors-DTvfh8lb.js";
147
3
  //#region src/auth/config.ts
148
4
  function frozenArray(value) {
149
5
  return value === void 0 ? void 0 : Object.freeze([...value]);
@@ -178,4 +34,4 @@ function issuer(options) {
178
34
  const oauth = Object.freeze({ issuer });
179
35
  const auth = Object.freeze({ oauth });
180
36
  //#endregion
181
- export { ToolContext, ToolError, auth, defineMcp, defineTool, setLogLevel };
37
+ export { AuthContext, ToolContext, ToolError, auth, defineMcp, defineTool, setLogLevel };
@@ -1,4 +1,4 @@
1
- import "./types-C6O4ciic.cjs";
1
+ import "./types-S6J_QTXw.cjs";
2
2
  //#region src/manifest/io.d.ts
3
3
  /**
4
4
  * Shape every MCP Vite plugin exposes on its `api` so `runExtract` can read
@@ -1,5 +1,5 @@
1
1
  import { t as jsonSchemaFromDefinition } from "./schema-CW1jKvio.js";
2
- import { t as version } from "./package-ZzwBAUf7.js";
2
+ import { t as version } from "./package-BAYb-3dX.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,7 +23,8 @@ 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")
26
+ outputSchema: schemaToJsonSchema(tool.outputSchema, "output"),
27
+ ...tool.enabled ? { conditional: true } : {}
27
28
  }))
28
29
  };
29
30
  }
@@ -1,4 +1,4 @@
1
- import "./types-C6O4ciic.js";
1
+ import "./types-S6J_QTXw.js";
2
2
  //#region src/manifest/io.d.ts
3
3
  /**
4
4
  * Shape every MCP Vite plugin exposes on its `api` so `runExtract` can read
@@ -1,5 +1,5 @@
1
1
  const require_schema = require("./schema-D3vClxb7.cjs");
2
- const require_package = require("./package-ClsLrfmB.cjs");
2
+ const require_package = require("./package-DlouusYQ.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,7 +23,8 @@ 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")
26
+ outputSchema: schemaToJsonSchema(tool.outputSchema, "output"),
27
+ ...tool.enabled ? { conditional: true } : {}
27
28
  }))
28
29
  };
29
30
  }
@@ -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 { 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-K-QaLAV0.js";
3
+ import { a as ToolContext, c as toolRequiresAppContext, i as AuthContext, n as errorSummary, r as resolveToolErrorMessage } from "./errors-DTvfh8lb.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-D4BjUpgU.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,6 +117,52 @@ 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
+ }
120
166
  function statelessMethodNotAllowed(allow) {
121
167
  return Response.json({
122
168
  jsonrpc: "2.0",
@@ -191,12 +237,12 @@ function toolRequestContext(sdkCtx, protocol) {
191
237
  sendProgress
192
238
  };
193
239
  }
194
- async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
240
+ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx, appContext) {
195
241
  const endUserId = auth?.principal.sub;
196
242
  const start = nowMs();
197
243
  let result;
198
244
  try {
199
- result = await tool.handler(args, new ToolContext(auth, toolRequestContext(sdkCtx, protocol)));
245
+ result = await tool.handler(args, new ToolContext(auth, toolRequestContext(sdkCtx, protocol), appContext));
200
246
  } catch (err) {
201
247
  const callerMessage = resolveToolErrorMessage(err);
202
248
  if (callerMessage === void 0) {
@@ -254,10 +300,10 @@ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
254
300
  });
255
301
  return result;
256
302
  }
257
- function adaptToolCallback(tool, auth, recorder, protocol) {
303
+ function adaptToolCallback(tool, auth, recorder, protocol, appContext) {
258
304
  return async (first, second) => {
259
305
  const sdkCtx = tool.inputSchema ? second : first;
260
- const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx);
306
+ const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx, appContext);
261
307
  return {
262
308
  content: result.content ?? [],
263
309
  structuredContent: result.structuredContent,
@@ -265,23 +311,52 @@ function adaptToolCallback(tool, auth, recorder, protocol) {
265
311
  };
266
312
  };
267
313
  }
268
- function buildServer(mcp, auth, recorder, era) {
314
+ async function buildServer(mcp, auth, recorder, era, signal, operations) {
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
+ };
269
332
  const server = new McpServer({
270
333
  name: mcp.name,
271
334
  version: mcp.version,
272
335
  title: mcp.title
273
336
  }, {
274
337
  instructions: mcp.instructions,
275
- capabilities: { tools: { listChanged: false } }
338
+ capabilities: { tools: { listChanged: false } },
339
+ cacheHints: {
340
+ "tools/list": cacheHint,
341
+ "server/discover": cacheHint
342
+ }
276
343
  });
277
- for (const tool of mcp.tools) {
344
+ for (const tool of selectedTools) {
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
+ }
278
353
  const config = {
279
354
  title: tool.title,
280
355
  description: tool.description,
281
356
  annotations: tool.annotations,
282
357
  ...tool.outputSchema ? { outputSchema: standardSchemaFromDefinition(tool.outputSchema) } : {}
283
358
  };
284
- const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION);
359
+ const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION, appContext);
285
360
  if (tool.inputSchema) server.registerTool(tool.name, {
286
361
  ...config,
287
362
  inputSchema: standardSchemaFromDefinition(tool.inputSchema)
@@ -302,26 +377,28 @@ function createMcpProtocolHandler(mcp, options = {}) {
302
377
  const handle = async (request, authResult, recorder) => {
303
378
  let protocolError;
304
379
  const reportTransportError = async (error) => {
380
+ const appContextFailure = error instanceof AppContextError;
305
381
  await recorder.emit({
306
382
  tool: null,
307
383
  method: "transport",
308
- outcome: "transport_error",
384
+ outcome: appContextFailure ? "app_context_error" : "transport_error",
309
385
  durationMs: 0,
310
386
  endUserId: authResult.auth?.principal.sub
311
387
  });
312
- log.error("mcp.transport_error", {
313
- ...error === void 0 ? {} : describeError(error),
388
+ log.error(appContextFailure ? "mcp.app_context_error" : "mcp.transport_error", {
389
+ ...error === void 0 ? {} : describeError(appContextFailure ? error.cause : error),
314
390
  outcome: "500 internal error"
315
391
  });
316
392
  };
317
393
  try {
318
- const response = await createMcpHandler(({ era }) => buildServer(mcp, authResult.auth, recorder, era), {
394
+ const classified = mcp.createAppContext ? await classifyRequest(request) : void 0;
395
+ const response = await createMcpHandler(({ era, requestInfo }) => buildServer(mcp, authResult.auth, recorder, era, requestInfo?.signal ?? request.signal, classified?.operations), {
319
396
  legacy: "stateless",
320
397
  maxSubscriptions: 0,
321
398
  onerror: (error) => {
322
399
  protocolError = error;
323
400
  }
324
- }).fetch(request);
401
+ }).fetch(request, classified?.parsedBody === void 0 ? void 0 : { parsedBody: classified.parsedBody });
325
402
  if (response.status >= 500) await reportTransportError(protocolError);
326
403
  return response;
327
404
  } catch (err) {
@@ -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-Cr95rSkB.cjs");
4
- const require_cors = require("./cors-DheH0sX2.cjs");
3
+ const require_errors = require("./errors-CdrGi5aP.cjs");
4
+ const require_cors = require("./cors-0ZCwmwyK.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,6 +117,52 @@ 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
+ }
120
166
  function statelessMethodNotAllowed(allow) {
121
167
  return Response.json({
122
168
  jsonrpc: "2.0",
@@ -191,12 +237,12 @@ function toolRequestContext(sdkCtx, protocol) {
191
237
  sendProgress
192
238
  };
193
239
  }
194
- async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
240
+ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx, appContext) {
195
241
  const endUserId = auth?.principal.sub;
196
242
  const start = require_cors.nowMs();
197
243
  let result;
198
244
  try {
199
- result = await tool.handler(args, new require_errors.ToolContext(auth, toolRequestContext(sdkCtx, protocol)));
245
+ result = await tool.handler(args, new require_errors.ToolContext(auth, toolRequestContext(sdkCtx, protocol), appContext));
200
246
  } catch (err) {
201
247
  const callerMessage = require_errors.resolveToolErrorMessage(err);
202
248
  if (callerMessage === void 0) {
@@ -254,10 +300,10 @@ async function invokeTool(tool, auth, recorder, args, protocol, sdkCtx) {
254
300
  });
255
301
  return result;
256
302
  }
257
- function adaptToolCallback(tool, auth, recorder, protocol) {
303
+ function adaptToolCallback(tool, auth, recorder, protocol, appContext) {
258
304
  return async (first, second) => {
259
305
  const sdkCtx = tool.inputSchema ? second : first;
260
- const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx);
306
+ const result = await invokeTool(tool, auth, recorder, tool.inputSchema ? first ?? {} : {}, protocol, sdkCtx, appContext);
261
307
  return {
262
308
  content: result.content ?? [],
263
309
  structuredContent: result.structuredContent,
@@ -265,23 +311,52 @@ function adaptToolCallback(tool, auth, recorder, protocol) {
265
311
  };
266
312
  };
267
313
  }
268
- function buildServer(mcp, auth, recorder, era) {
314
+ async function buildServer(mcp, auth, recorder, era, signal, operations) {
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
+ };
269
332
  const server = new _modelcontextprotocol_server.McpServer({
270
333
  name: mcp.name,
271
334
  version: mcp.version,
272
335
  title: mcp.title
273
336
  }, {
274
337
  instructions: mcp.instructions,
275
- capabilities: { tools: { listChanged: false } }
338
+ capabilities: { tools: { listChanged: false } },
339
+ cacheHints: {
340
+ "tools/list": cacheHint,
341
+ "server/discover": cacheHint
342
+ }
276
343
  });
277
- for (const tool of mcp.tools) {
344
+ for (const tool of selectedTools) {
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
+ }
278
353
  const config = {
279
354
  title: tool.title,
280
355
  description: tool.description,
281
356
  annotations: tool.annotations,
282
357
  ...tool.outputSchema ? { outputSchema: standardSchemaFromDefinition(tool.outputSchema) } : {}
283
358
  };
284
- const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION);
359
+ const callback = adaptToolCallback(tool, auth, recorder, era === "legacy" ? "legacy" : MODERN_PROTOCOL_VERSION, appContext);
285
360
  if (tool.inputSchema) server.registerTool(tool.name, {
286
361
  ...config,
287
362
  inputSchema: standardSchemaFromDefinition(tool.inputSchema)
@@ -302,26 +377,28 @@ function createMcpProtocolHandler(mcp, options = {}) {
302
377
  const handle = async (request, authResult, recorder) => {
303
378
  let protocolError;
304
379
  const reportTransportError = async (error) => {
380
+ const appContextFailure = error instanceof AppContextError;
305
381
  await recorder.emit({
306
382
  tool: null,
307
383
  method: "transport",
308
- outcome: "transport_error",
384
+ outcome: appContextFailure ? "app_context_error" : "transport_error",
309
385
  durationMs: 0,
310
386
  endUserId: authResult.auth?.principal.sub
311
387
  });
312
- require_logger.log.error("mcp.transport_error", {
313
- ...error === void 0 ? {} : require_logger.describeError(error),
388
+ require_logger.log.error(appContextFailure ? "mcp.app_context_error" : "mcp.transport_error", {
389
+ ...error === void 0 ? {} : require_logger.describeError(appContextFailure ? error.cause : error),
314
390
  outcome: "500 internal error"
315
391
  });
316
392
  };
317
393
  try {
318
- const response = await (0, _modelcontextprotocol_server.createMcpHandler)(({ era }) => buildServer(mcp, authResult.auth, recorder, era), {
394
+ const classified = mcp.createAppContext ? await classifyRequest(request) : void 0;
395
+ const response = await (0, _modelcontextprotocol_server.createMcpHandler)(({ era, requestInfo }) => buildServer(mcp, authResult.auth, recorder, era, requestInfo?.signal ?? request.signal, classified?.operations), {
319
396
  legacy: "stateless",
320
397
  maxSubscriptions: 0,
321
398
  onerror: (error) => {
322
399
  protocolError = error;
323
400
  }
324
- }).fetch(request);
401
+ }).fetch(request, classified?.parsedBody === void 0 ? void 0 : { parsedBody: classified.parsedBody });
325
402
  if (response.status >= 500) await reportTransportError(protocolError);
326
403
  return response;
327
404
  } catch (err) {
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "2.0.4-rc.0";
2
+ var version = "2.1.0-rc.0";
3
3
  //#endregion
4
4
  export { version as t };
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "2.0.4-rc.0";
2
+ var version = "2.1.0-rc.0";
3
3
  //#endregion
4
4
  Object.defineProperty(exports, "version", {
5
5
  enumerable: true,
@@ -1,3 +1,3 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_mcp = require("../../mcp-CY55D6Km.cjs");
2
+ const require_mcp = require("../../mcp-Q_rjpR99.cjs");
3
3
  exports.createMcpProtocolHandler = require_mcp.createMcpProtocolHandler;
@@ -1,6 +1,6 @@
1
- import { d as McpDefinition } from "../../types-C6O4ciic.cjs";
2
- import { t as MetricsRecorder } from "../../base-DAkOPRay.cjs";
3
- import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-oCEahmRv.cjs";
1
+ import { p as McpDefinition } from "../../types-S6J_QTXw.cjs";
2
+ import { t as MetricsRecorder } from "../../base-4G2k3bMl.cjs";
3
+ import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-BC4TM__8.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 { d as McpDefinition } from "../../types-C6O4ciic.js";
2
- import { t as MetricsRecorder } from "../../base-DnCoJOZN.js";
3
- import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-B5VMSzcN.js";
1
+ import { p as McpDefinition } from "../../types-S6J_QTXw.js";
2
+ import { t as MetricsRecorder } from "../../base-BnlJz6TE.js";
3
+ import { n as ScheduleBackground, t as McpRuntimeOptions } from "../../authorize-DEsM-zTN.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-TJZHxHwb.js";
1
+ import { t as createMcpProtocolHandler } from "../../mcp-CuHyVOZK.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-DheH0sX2.cjs");
3
+ const require_cors = require("../cors-0ZCwmwyK.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 { d as McpDefinition } from "../types-C6O4ciic.cjs";
2
- import { t as MetricsRecorder } from "../base-DAkOPRay.cjs";
3
- import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-oCEahmRv.cjs";
1
+ import { p as McpDefinition } from "../types-S6J_QTXw.cjs";
2
+ import { t as MetricsRecorder } from "../base-4G2k3bMl.cjs";
3
+ import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-BC4TM__8.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 { d as McpDefinition } from "../types-C6O4ciic.js";
2
- import { t as MetricsRecorder } from "../base-DnCoJOZN.js";
3
- import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-B5VMSzcN.js";
1
+ import { p as McpDefinition } from "../types-S6J_QTXw.js";
2
+ import { t as MetricsRecorder } from "../base-BnlJz6TE.js";
3
+ import { n as ScheduleBackground, t as McpRuntimeOptions } from "../authorize-DEsM-zTN.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-K-QaLAV0.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-D4BjUpgU.js";
3
3
  //#region src/protocols/oauth-metadata.ts
4
4
  function notFound() {
5
5
  return new Response(JSON.stringify({ error: "not found" }), {