@lovable.dev/mcp-js 0.22.1 → 0.22.2-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 (87) hide show
  1. package/dist/authorize-CumVyk7p.d.cts +27 -0
  2. package/dist/authorize-D6p4-9_D.d.ts +27 -0
  3. package/dist/base-DCe0kP79.d.cts +29 -0
  4. package/dist/base-DCe0kP79.d.ts +29 -0
  5. package/dist/cli/extract-manifest.cjs +116 -201
  6. package/dist/cli/extract-manifest.d.cts +1 -1
  7. package/dist/cli/extract-manifest.d.ts +1 -1
  8. package/dist/cli/extract-manifest.js +117 -156
  9. package/dist/content-D5LJAHyM.js +12 -0
  10. package/dist/content-NCYIGgOb.cjs +17 -0
  11. package/dist/context-BweeEcoA.cjs +56 -0
  12. package/dist/context-CIpPzN7P.js +51 -0
  13. package/dist/cors-CSDhBjFd.cjs +913 -0
  14. package/dist/cors-rWp_tbLZ.js +830 -0
  15. package/dist/forwarded--h4efJy-.js +43 -0
  16. package/dist/forwarded-Pi8Hs5Ps.cjs +48 -0
  17. package/dist/fs-errors-CWNzOV75.cjs +11 -0
  18. package/dist/fs-errors-PA2t1TIp.js +6 -0
  19. package/dist/index.cjs +129 -329
  20. package/dist/index.d.cts +26 -26
  21. package/dist/index.d.ts +26 -26
  22. package/dist/index.js +118 -177
  23. package/dist/{io-D4srzRKc.d.ts → io-CfSPxeBN.d.ts} +6 -4
  24. package/dist/io-DPYvBqET.d.cts +15 -0
  25. package/dist/list-tools-B4TTPEl1.d.cts +8 -0
  26. package/dist/list-tools-CFUX-uo-.cjs +57 -0
  27. package/dist/list-tools-DVJrjtmH.js +46 -0
  28. package/dist/list-tools-bh6-eqZM.d.ts +8 -0
  29. package/dist/logger-2OXtfiIW.js +141 -0
  30. package/dist/logger-BqPOa_E1.cjs +194 -0
  31. package/dist/mcp-BNcpj8o7.cjs +128 -0
  32. package/dist/mcp-Bx3bJHzH.js +123 -0
  33. package/dist/metadata-path-CAkNcfyY.js +12 -0
  34. package/dist/metadata-path-zd7NSNoa.cjs +17 -0
  35. package/dist/package-CgwD4Ywz.js +4 -0
  36. package/dist/package-DzstF8Ih.cjs +9 -0
  37. package/dist/paths-IS65L6TA.js +7 -0
  38. package/dist/paths-OP318a6c.cjs +18 -0
  39. package/dist/protocols/mcp/index.cjs +3 -750
  40. package/dist/protocols/mcp/index.d.cts +6 -7
  41. package/dist/protocols/mcp/index.d.ts +6 -7
  42. package/dist/protocols/mcp/index.js +2 -12
  43. package/dist/protocols/oauth-metadata.cjs +48 -539
  44. package/dist/protocols/oauth-metadata.d.cts +5 -6
  45. package/dist/protocols/oauth-metadata.d.ts +5 -6
  46. package/dist/protocols/oauth-metadata.js +52 -10
  47. package/dist/protocols/rest/index.cjs +5 -843
  48. package/dist/protocols/rest/index.d.cts +7 -10
  49. package/dist/protocols/rest/index.d.ts +7 -10
  50. package/dist/protocols/rest/index.js +3 -16
  51. package/dist/rest-BRshnow2.js +117 -0
  52. package/dist/rest-C4ZEGSIV.cjs +122 -0
  53. package/dist/stacks/supabase/index.cjs +76 -1318
  54. package/dist/stacks/supabase/index.d.cts +29 -30
  55. package/dist/stacks/supabase/index.d.ts +29 -30
  56. package/dist/stacks/supabase/index.js +73 -89
  57. package/dist/stacks/supabase/vite.cjs +258 -287
  58. package/dist/stacks/supabase/vite.d.cts +24 -24
  59. package/dist/stacks/supabase/vite.d.ts +24 -24
  60. package/dist/stacks/supabase/vite.js +252 -252
  61. package/dist/stacks/tanstack/index.cjs +42 -1272
  62. package/dist/stacks/tanstack/index.d.cts +8 -9
  63. package/dist/stacks/tanstack/index.d.ts +8 -9
  64. package/dist/stacks/tanstack/index.js +36 -41
  65. package/dist/stacks/tanstack/vite.cjs +223 -312
  66. package/dist/stacks/tanstack/vite.d.cts +80 -81
  67. package/dist/stacks/tanstack/vite.d.ts +80 -81
  68. package/dist/stacks/tanstack/vite.js +216 -282
  69. package/dist/types-BYdYYTjk.d.cts +321 -0
  70. package/dist/types-BYdYYTjk.d.ts +321 -0
  71. package/package.json +4 -4
  72. package/dist/authorize-BMeXd_Sh.d.ts +0 -25
  73. package/dist/base-CM-KCpp6.d.ts +0 -28
  74. package/dist/chunk-5HVSJCKE.js +0 -114
  75. package/dist/chunk-6DXGZZA4.js +0 -6
  76. package/dist/chunk-6QFZYYUV.js +0 -11
  77. package/dist/chunk-6SZOFKGH.js +0 -58
  78. package/dist/chunk-H37EB22A.js +0 -125
  79. package/dist/chunk-IFDWUM7L.js +0 -741
  80. package/dist/chunk-IXZIFYO6.js +0 -79
  81. package/dist/chunk-MA5H6PSF.js +0 -46
  82. package/dist/chunk-TJN33K5U.js +0 -141
  83. package/dist/chunk-UQK5UO6C.js +0 -26
  84. package/dist/chunk-XQWJN6DC.js +0 -14
  85. package/dist/chunk-Y3ZFPEQH.js +0 -8
  86. package/dist/chunk-ZQXSWTPU.js +0 -6
  87. package/dist/types-qqrmJ736.d.ts +0 -321
@@ -1,109 +1,85 @@
1
- import {
2
- OAUTH_PROTECTED_RESOURCE_METADATA_PATH
3
- } from "../../chunk-6DXGZZA4.js";
4
- import {
5
- isFileMissing
6
- } from "../../chunk-Y3ZFPEQH.js";
7
-
8
- // src/stacks/tanstack/vite.ts
9
- import { lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "fs";
10
- import { dirname, join, relative, resolve, sep } from "path";
11
- var GENERATED_BANNER = "// AUTO-GENERATED by @lovable.dev/mcp-js \u2014 do not edit. Regenerated by the Vite plugin.\n// To take ownership, delete this banner line; the plugin then leaves the file alone.";
1
+ import "../../metadata-path-CAkNcfyY.js";
2
+ import { t as isFileMissing } from "../../fs-errors-PA2t1TIp.js";
3
+ import { lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, relative, resolve, sep } from "node:path";
5
+ //#region src/stacks/tanstack/vite.ts
6
+ const GENERATED_BANNER = "// AUTO-GENERATED by @lovable.dev/mcp-js — do not edit. Regenerated by the Vite plugin.\n// To take ownership, delete this banner line; the plugin then leaves the file alone.";
12
7
  function normalizePath(p) {
13
- return p.split(sep).join("/");
8
+ return p.split(sep).join("/");
14
9
  }
15
10
  function assertContains(parent, child, label) {
16
- if (child !== parent && !child.startsWith(parent + sep)) {
17
- throw new Error(`@lovable.dev/mcp-js: ${label} must resolve under ${parent}, got ${child}`);
18
- }
11
+ if (child !== parent && !child.startsWith(parent + sep)) throw new Error(`@lovable.dev/mcp-js: ${label} must resolve under ${parent}, got ${child}`);
19
12
  }
20
13
  function wellKnownRouteFile(routesDir, urlPath) {
21
- const segments = urlPath.replace(/^\//, "").split("/");
22
- const fileSegments = segments.map((segment, index) => {
23
- const escaped = segment.startsWith(".") ? `[${segment}]` : segment;
24
- return index === segments.length - 1 ? `${escaped}.ts` : escaped;
25
- });
26
- return resolve(routesDir, ...fileSegments);
14
+ const segments = urlPath.replace(/^\//, "").split("/");
15
+ return resolve(routesDir, ...segments.map((segment, index) => {
16
+ const escaped = segment.startsWith(".") ? `[${segment}]` : segment;
17
+ return index === segments.length - 1 ? `${escaped}.ts` : escaped;
18
+ }));
27
19
  }
28
20
  function resolveRestRoutes(routesDir, mcpUrlPath) {
29
- const parentSegments = mcpUrlPath.replace(/^\/+/, "").replace(/\/+$/, "").split("/").slice(0, -1);
30
- const restDir = resolve(routesDir, ...parentSegments, "[.mcp]");
31
- const restUrlBase = `/${[...parentSegments, ".mcp"].join("/")}`;
32
- return {
33
- listToolsRouteFile: resolve(restDir, "list-tools.ts"),
34
- invokeToolRouteFile: resolve(restDir, "invoke-tool", "$tool.ts"),
35
- listToolsLiteral: `${restUrlBase}/list-tools`,
36
- invokeToolLiteral: `${restUrlBase}/invoke-tool/$tool`
37
- };
21
+ const parentSegments = mcpUrlPath.replace(/^\/+/, "").replace(/\/+$/, "").split("/").slice(0, -1);
22
+ const restDir = resolve(routesDir, ...parentSegments, "[.mcp]");
23
+ const restUrlBase = `/${[...parentSegments, ".mcp"].join("/")}`;
24
+ return {
25
+ listToolsRouteFile: resolve(restDir, "list-tools.ts"),
26
+ invokeToolRouteFile: resolve(restDir, "invoke-tool", "$tool.ts"),
27
+ listToolsLiteral: `${restUrlBase}/list-tools`,
28
+ invokeToolLiteral: `${restUrlBase}/invoke-tool/$tool`
29
+ };
38
30
  }
39
31
  function resolveAllRoutes(projectRoot, routesDirOption, routeFileName, mcpUrlPath, metadataUrlPath) {
40
- const routesDir = resolve(projectRoot, routesDirOption);
41
- assertContains(projectRoot, routesDir, `routesDir "${routesDirOption}"`);
42
- const mcpRouteFile = resolve(routesDir, routeFileName);
43
- assertContains(routesDir, mcpRouteFile, `routeFileName "${routeFileName}"`);
44
- const metadataRouteFile = wellKnownRouteFile(routesDir, metadataUrlPath);
45
- assertContains(routesDir, metadataRouteFile, `metadataPath "${metadataUrlPath}"`);
46
- const rest = resolveRestRoutes(routesDir, mcpUrlPath);
47
- assertContains(routesDir, rest.listToolsRouteFile, `REST routes for path "${mcpUrlPath}"`);
48
- assertContains(routesDir, rest.invokeToolRouteFile, `REST routes for path "${mcpUrlPath}"`);
49
- return { routesDir, mcpRouteFile, metadataRouteFile, ...rest };
32
+ const routesDir = resolve(projectRoot, routesDirOption);
33
+ assertContains(projectRoot, routesDir, `routesDir "${routesDirOption}"`);
34
+ const mcpRouteFile = resolve(routesDir, routeFileName);
35
+ assertContains(routesDir, mcpRouteFile, `routeFileName "${routeFileName}"`);
36
+ const metadataRouteFile = wellKnownRouteFile(routesDir, metadataUrlPath);
37
+ assertContains(routesDir, metadataRouteFile, `metadataPath "${metadataUrlPath}"`);
38
+ const rest = resolveRestRoutes(routesDir, mcpUrlPath);
39
+ assertContains(routesDir, rest.listToolsRouteFile, `REST routes for path "${mcpUrlPath}"`);
40
+ assertContains(routesDir, rest.invokeToolRouteFile, `REST routes for path "${mcpUrlPath}"`);
41
+ return {
42
+ routesDir,
43
+ mcpRouteFile,
44
+ metadataRouteFile,
45
+ ...rest
46
+ };
50
47
  }
51
48
  function assertUrlPathShape(urlPath) {
52
- if (!urlPath.startsWith("/")) {
53
- throw new Error(`@lovable.dev/mcp-js: path must start with "/", got "${urlPath}"`);
54
- }
55
- if (/\/{2,}/.test(urlPath)) {
56
- throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" contains empty segments ("//")`);
57
- }
58
- const trimmed = urlPath.replace(/^\/+/, "").replace(/\/+$/, "");
59
- if (!trimmed) {
60
- throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" has no route segment`);
61
- }
62
- if (!/^[a-zA-Z0-9_\-/]+$/.test(trimmed)) {
63
- throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" contains unsupported characters`);
64
- }
65
- return trimmed;
49
+ if (!urlPath.startsWith("/")) throw new Error(`@lovable.dev/mcp-js: path must start with "/", got "${urlPath}"`);
50
+ if (/\/{2,}/.test(urlPath)) throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" contains empty segments ("//")`);
51
+ const trimmed = urlPath.replace(/^\/+/, "").replace(/\/+$/, "");
52
+ if (!trimmed) throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" has no route segment`);
53
+ if (!/^[a-zA-Z0-9_\-/]+$/.test(trimmed)) throw new Error(`@lovable.dev/mcp-js: path "${urlPath}" contains unsupported characters`);
54
+ return trimmed;
66
55
  }
67
56
  function deriveRouteFileName(urlPath) {
68
- return `${assertUrlPathShape(urlPath)}.ts`;
57
+ return `${assertUrlPathShape(urlPath)}.ts`;
69
58
  }
70
59
  function assertMetadataPathShape(metadataPath) {
71
- if (!metadataPath.startsWith("/")) {
72
- throw new Error(`@lovable.dev/mcp-js: metadataPath must start with "/", got "${metadataPath}"`);
73
- }
74
- if (/\/{2,}/.test(metadataPath)) {
75
- throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" contains empty segments ("//")`);
76
- }
77
- if (/(^|\/)\.\.(\/|$)/.test(metadataPath)) {
78
- throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" must not contain ".." segments`);
79
- }
80
- const trimmed = metadataPath.replace(/^\/+/, "").replace(/\/+$/, "");
81
- if (!trimmed) {
82
- throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" has no route segment`);
83
- }
84
- if (!/^[a-zA-Z0-9_\-./]+$/.test(trimmed)) {
85
- throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" contains unsupported characters`);
86
- }
60
+ if (!metadataPath.startsWith("/")) throw new Error(`@lovable.dev/mcp-js: metadataPath must start with "/", got "${metadataPath}"`);
61
+ if (/\/{2,}/.test(metadataPath)) throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" contains empty segments ("//")`);
62
+ if (/(^|\/)\.\.(\/|$)/.test(metadataPath)) throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" must not contain ".." segments`);
63
+ const trimmed = metadataPath.replace(/^\/+/, "").replace(/\/+$/, "");
64
+ if (!trimmed) throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" has no route segment`);
65
+ if (!/^[a-zA-Z0-9_\-./]+$/.test(trimmed)) throw new Error(`@lovable.dev/mcp-js: metadataPath "${metadataPath}" contains unsupported characters`);
87
66
  }
88
67
  function canonicalUrlPath(urlPath) {
89
- return `/${urlPath.replace(/^\/+/, "").replace(/\/+$/, "")}`;
68
+ return `/${urlPath.replace(/^\/+/, "").replace(/\/+$/, "")}`;
90
69
  }
91
70
  function relativeImportSpecifier(routeFile, target) {
92
- const rel = normalizePath(relative(dirname(routeFile), target));
93
- const withoutExt = rel.replace(/\.ts$/, "");
94
- return withoutExt.startsWith(".") ? withoutExt : `./${withoutExt}`;
71
+ const withoutExt = normalizePath(relative(dirname(routeFile), target)).replace(/\.ts$/, "");
72
+ return withoutExt.startsWith(".") ? withoutExt : `./${withoutExt}`;
95
73
  }
96
74
  function buildRouteSource(route, resourcePath, metadataPath, trustForwardedHost, mcpEntry, projectRoot) {
97
- const mcpImport = relativeImportSpecifier(route.file, mcpEntry);
98
- const routeRel = normalizePath(relative(projectRoot, route.file));
99
- const note = route.spaFallbackNote ? " // ANY: TanStack returns SPA HTML for methods not in `handlers`; the SDK 405s instead.\n" : "";
100
- const optionEntries = [`resourcePath: "${resourcePath}"`];
101
- if (metadataPath !== void 0)
102
- optionEntries.push(`metadataPath: "${metadataPath}"`);
103
- if (trustForwardedHost)
104
- optionEntries.push("trustForwardedHost: true");
105
- const runtimeOptions = `{ ${optionEntries.join(", ")} }`;
106
- return `${GENERATED_BANNER}
75
+ const mcpImport = relativeImportSpecifier(route.file, mcpEntry);
76
+ const routeRel = normalizePath(relative(projectRoot, route.file));
77
+ const note = route.spaFallbackNote ? " // ANY: TanStack returns SPA HTML for methods not in `handlers`; the SDK 405s instead.\n" : "";
78
+ const optionEntries = [`resourcePath: "${resourcePath}"`];
79
+ if (metadataPath !== void 0) optionEntries.push(`metadataPath: "${metadataPath}"`);
80
+ if (trustForwardedHost) optionEntries.push("trustForwardedHost: true");
81
+ const runtimeOptions = `{ ${optionEntries.join(", ")} }`;
82
+ return `${GENERATED_BANNER}
107
83
  // route: ${route.routeLiteral}
108
84
  // emitted to: ${routeRel}
109
85
 
@@ -122,210 +98,168 @@ ${note} ANY: ${route.handlerFactory}(mcp, ${runtimeOptions}),
122
98
  });
123
99
  `;
124
100
  }
101
+ /**
102
+ * Writes `content` to `file` if it differs from what's there. Refuses to
103
+ * overwrite files without `GENERATED_BANNER` — the banner is the consent token.
104
+ */
125
105
  function hasGeneratedBanner(content) {
126
- return content.replace(/\r\n/g, "\n").startsWith(GENERATED_BANNER);
106
+ return content.replace(/\r\n/g, "\n").startsWith(GENERATED_BANNER);
127
107
  }
128
108
  function writeIfChanged(file, content) {
129
- let existing;
130
- try {
131
- existing = readFileSync(file, "utf8");
132
- } catch (err) {
133
- if (!isFileMissing(err))
134
- throw err;
135
- }
136
- if (existing !== void 0) {
137
- if (!hasGeneratedBanner(existing)) {
138
- throw new Error(
139
- `@lovable.dev/mcp-js: refusing to overwrite user-authored route at ${file}. Delete it or move it first.`
140
- );
141
- }
142
- if (existing === content)
143
- return false;
144
- }
145
- mkdirSync(dirname(file), { recursive: true });
146
- writeFileSync(file, content, "utf8");
147
- return true;
109
+ let existing;
110
+ try {
111
+ existing = readFileSync(file, "utf8");
112
+ } catch (err) {
113
+ if (!isFileMissing(err)) throw err;
114
+ }
115
+ if (existing !== void 0) {
116
+ if (!hasGeneratedBanner(existing)) throw new Error(`@lovable.dev/mcp-js: refusing to overwrite user-authored route at ${file}. Delete it or move it first.`);
117
+ if (existing === content) return false;
118
+ }
119
+ mkdirSync(dirname(file), { recursive: true });
120
+ writeFileSync(file, content, "utf8");
121
+ return true;
148
122
  }
149
123
  function fileStartsWithBanner(file) {
150
- try {
151
- return hasGeneratedBanner(readFileSync(file, "utf8"));
152
- } catch (err) {
153
- if (isFileMissing(err))
154
- return false;
155
- throw err;
156
- }
124
+ try {
125
+ return hasGeneratedBanner(readFileSync(file, "utf8"));
126
+ } catch (err) {
127
+ if (isFileMissing(err)) return false;
128
+ throw err;
129
+ }
157
130
  }
158
131
  function findAdoptedFiles(routesDir) {
159
- const adopted = [];
160
- const visit = (dir) => {
161
- let entries;
162
- try {
163
- entries = readdirSync(dir);
164
- } catch (err) {
165
- if (isFileMissing(err))
166
- return;
167
- throw err;
168
- }
169
- for (const entry of entries) {
170
- const full = join(dir, entry);
171
- let stat;
172
- try {
173
- stat = lstatSync(full);
174
- } catch (err) {
175
- if (isFileMissing(err))
176
- continue;
177
- throw err;
178
- }
179
- if (stat.isDirectory()) {
180
- visit(full);
181
- } else if (entry.endsWith(".ts") && fileStartsWithBanner(full)) {
182
- adopted.push(full);
183
- }
184
- }
185
- };
186
- visit(routesDir);
187
- return adopted;
132
+ const adopted = [];
133
+ const visit = (dir) => {
134
+ let entries;
135
+ try {
136
+ entries = readdirSync(dir);
137
+ } catch (err) {
138
+ if (isFileMissing(err)) return;
139
+ throw err;
140
+ }
141
+ for (const entry of entries) {
142
+ const full = join(dir, entry);
143
+ let stat;
144
+ try {
145
+ stat = lstatSync(full);
146
+ } catch (err) {
147
+ if (isFileMissing(err)) continue;
148
+ throw err;
149
+ }
150
+ if (stat.isDirectory()) visit(full);
151
+ else if (entry.endsWith(".ts") && fileStartsWithBanner(full)) adopted.push(full);
152
+ }
153
+ };
154
+ visit(routesDir);
155
+ return adopted;
188
156
  }
157
+ /**
158
+ * Generate the TanStack route(s) that mount the MCP server.
159
+ *
160
+ * Place this in your `vite.config.ts` plugins array. Emits during
161
+ * `configResolved` (so dev-server boot and the TanStack file-router both
162
+ * see the routes on the first request) and re-emits when the MCP entry
163
+ * file appears or disappears during dev.
164
+ *
165
+ * The `.lovable/mcp/manifest.json` snapshot is produced separately by the
166
+ * `lovable-mcp-extract-manifest` CLI (run by a host platform at build/commit
167
+ * time) — not by this plugin.
168
+ */
189
169
  function mcpPlugin(options = {}) {
190
- const mcpEntryOption = options.mcpEntry ?? "src/lib/mcp/index.ts";
191
- const routesDirOption = options.routesDir ?? "src/routes";
192
- const rawUrlPath = options.path ?? "/mcp";
193
- assertUrlPathShape(rawUrlPath);
194
- const routeFileName = options.routeFileName ?? deriveRouteFileName(rawUrlPath);
195
- const urlPath = canonicalUrlPath(rawUrlPath);
196
- const emitRestRoutes = options.restRoutes !== false;
197
- const emitProtectedResourceMetadataRoute = options.protectedResourceMetadataRoute !== false;
198
- if (options.metadataPath !== void 0) {
199
- if (!emitProtectedResourceMetadataRoute) {
200
- throw new Error(
201
- `@lovable.dev/mcp-js: metadataPath sets where the protected-resource metadata route is served, so it can't be combined with protectedResourceMetadataRoute: false.`
202
- );
203
- }
204
- assertMetadataPathShape(options.metadataPath);
205
- }
206
- const metadataUrlPath = canonicalUrlPath(options.metadataPath ?? OAUTH_PROTECTED_RESOURCE_METADATA_PATH);
207
- const injectedMetadataPath = emitProtectedResourceMetadataRoute ? metadataUrlPath : void 0;
208
- const trustForwardedHost = options.trustForwardedHost !== false;
209
- let projectRoot = process.cwd();
210
- let mcpEntry = resolve(projectRoot, mcpEntryOption);
211
- let {
212
- routesDir,
213
- mcpRouteFile,
214
- metadataRouteFile,
215
- listToolsRouteFile,
216
- invokeToolRouteFile,
217
- listToolsLiteral,
218
- invokeToolLiteral
219
- } = resolveAllRoutes(projectRoot, routesDirOption, routeFileName, urlPath, metadataUrlPath);
220
- const regenerate = () => {
221
- let mcpEntryExists = true;
222
- try {
223
- lstatSync(mcpEntry);
224
- } catch (err) {
225
- if (!isFileMissing(err))
226
- throw err;
227
- mcpEntryExists = false;
228
- }
229
- const expected = /* @__PURE__ */ new Set();
230
- if (mcpEntryExists) {
231
- const routes = [
232
- { file: mcpRouteFile, routeLiteral: urlPath, handlerFactory: "createTanStackMcpHandler" }
233
- ];
234
- if (emitProtectedResourceMetadataRoute) {
235
- routes.push({
236
- file: metadataRouteFile,
237
- routeLiteral: metadataUrlPath,
238
- handlerFactory: "createTanStackOAuthProtectedResourceMetadataHandler"
239
- });
240
- }
241
- if (emitRestRoutes) {
242
- routes.push(
243
- {
244
- file: listToolsRouteFile,
245
- routeLiteral: listToolsLiteral,
246
- handlerFactory: "createTanStackListToolsHandler",
247
- spaFallbackNote: true
248
- },
249
- {
250
- file: invokeToolRouteFile,
251
- routeLiteral: invokeToolLiteral,
252
- handlerFactory: "createTanStackInvokeToolHandler",
253
- spaFallbackNote: true
254
- }
255
- );
256
- }
257
- for (const route of routes) {
258
- expected.add(route.file);
259
- writeIfChanged(
260
- route.file,
261
- buildRouteSource(route, urlPath, injectedMetadataPath, trustForwardedHost, mcpEntry, projectRoot)
262
- );
263
- }
264
- }
265
- for (const file of findAdoptedFiles(routesDir)) {
266
- if (!expected.has(file)) {
267
- try {
268
- unlinkSync(file);
269
- } catch (err) {
270
- if (!isFileMissing(err))
271
- throw err;
272
- }
273
- }
274
- }
275
- };
276
- return {
277
- name: "@lovable.dev/mcp-js",
278
- // The extract CLI reads the resolved entry + URL path back through this
279
- // (via `resolveConfig().plugins`) so the manifest honors custom
280
- // `mcpEntry`/`path` instead of assuming the defaults. Getters because
281
- // `mcpEntry` is finalized in `configResolved`.
282
- api: {
283
- get mcpEntry() {
284
- return mcpEntry;
285
- },
286
- get urlPath() {
287
- return urlPath;
288
- }
289
- },
290
- configResolved(config) {
291
- projectRoot = config.root;
292
- mcpEntry = resolve(projectRoot, mcpEntryOption);
293
- ({
294
- routesDir,
295
- mcpRouteFile,
296
- metadataRouteFile,
297
- listToolsRouteFile,
298
- invokeToolRouteFile,
299
- listToolsLiteral,
300
- invokeToolLiteral
301
- } = resolveAllRoutes(projectRoot, routesDirOption, routeFileName, urlPath, metadataUrlPath));
302
- regenerate();
303
- },
304
- configureServer(server) {
305
- const onChange = (file) => {
306
- if (normalizePath(file) === normalizePath(mcpEntry)) {
307
- regenerate();
308
- }
309
- };
310
- server.watcher.on("add", onChange);
311
- server.watcher.on("change", onChange);
312
- server.watcher.on("unlink", onChange);
313
- server.watcher.once("close", () => {
314
- server.watcher.off("add", onChange);
315
- server.watcher.off("change", onChange);
316
- server.watcher.off("unlink", onChange);
317
- });
318
- },
319
- buildStart() {
320
- regenerate();
321
- }
322
- };
170
+ const mcpEntryOption = options.mcpEntry ?? "src/lib/mcp/index.ts";
171
+ const routesDirOption = options.routesDir ?? "src/routes";
172
+ const rawUrlPath = options.path ?? "/mcp";
173
+ assertUrlPathShape(rawUrlPath);
174
+ const routeFileName = options.routeFileName ?? deriveRouteFileName(rawUrlPath);
175
+ const urlPath = canonicalUrlPath(rawUrlPath);
176
+ const emitRestRoutes = options.restRoutes !== false;
177
+ const emitProtectedResourceMetadataRoute = options.protectedResourceMetadataRoute !== false;
178
+ if (options.metadataPath !== void 0) {
179
+ if (!emitProtectedResourceMetadataRoute) throw new Error(`@lovable.dev/mcp-js: metadataPath sets where the protected-resource metadata route is served, so it can't be combined with protectedResourceMetadataRoute: false.`);
180
+ assertMetadataPathShape(options.metadataPath);
181
+ }
182
+ const metadataUrlPath = canonicalUrlPath(options.metadataPath ?? "/.well-known/oauth-protected-resource");
183
+ const injectedMetadataPath = emitProtectedResourceMetadataRoute ? metadataUrlPath : void 0;
184
+ const trustForwardedHost = options.trustForwardedHost !== false;
185
+ let projectRoot = process.cwd();
186
+ let mcpEntry = resolve(projectRoot, mcpEntryOption);
187
+ let { routesDir, mcpRouteFile, metadataRouteFile, listToolsRouteFile, invokeToolRouteFile, listToolsLiteral, invokeToolLiteral } = resolveAllRoutes(projectRoot, routesDirOption, routeFileName, urlPath, metadataUrlPath);
188
+ const regenerate = () => {
189
+ let mcpEntryExists = true;
190
+ try {
191
+ lstatSync(mcpEntry);
192
+ } catch (err) {
193
+ if (!isFileMissing(err)) throw err;
194
+ mcpEntryExists = false;
195
+ }
196
+ const expected = /* @__PURE__ */ new Set();
197
+ if (mcpEntryExists) {
198
+ const routes = [{
199
+ file: mcpRouteFile,
200
+ routeLiteral: urlPath,
201
+ handlerFactory: "createTanStackMcpHandler"
202
+ }];
203
+ if (emitProtectedResourceMetadataRoute) routes.push({
204
+ file: metadataRouteFile,
205
+ routeLiteral: metadataUrlPath,
206
+ handlerFactory: "createTanStackOAuthProtectedResourceMetadataHandler"
207
+ });
208
+ if (emitRestRoutes) routes.push({
209
+ file: listToolsRouteFile,
210
+ routeLiteral: listToolsLiteral,
211
+ handlerFactory: "createTanStackListToolsHandler",
212
+ spaFallbackNote: true
213
+ }, {
214
+ file: invokeToolRouteFile,
215
+ routeLiteral: invokeToolLiteral,
216
+ handlerFactory: "createTanStackInvokeToolHandler",
217
+ spaFallbackNote: true
218
+ });
219
+ for (const route of routes) {
220
+ expected.add(route.file);
221
+ writeIfChanged(route.file, buildRouteSource(route, urlPath, injectedMetadataPath, trustForwardedHost, mcpEntry, projectRoot));
222
+ }
223
+ }
224
+ for (const file of findAdoptedFiles(routesDir)) if (!expected.has(file)) try {
225
+ unlinkSync(file);
226
+ } catch (err) {
227
+ if (!isFileMissing(err)) throw err;
228
+ }
229
+ };
230
+ return {
231
+ name: "@lovable.dev/mcp-js",
232
+ api: {
233
+ get mcpEntry() {
234
+ return mcpEntry;
235
+ },
236
+ get urlPath() {
237
+ return urlPath;
238
+ }
239
+ },
240
+ configResolved(config) {
241
+ projectRoot = config.root;
242
+ mcpEntry = resolve(projectRoot, mcpEntryOption);
243
+ ({routesDir, mcpRouteFile, metadataRouteFile, listToolsRouteFile, invokeToolRouteFile, listToolsLiteral, invokeToolLiteral} = resolveAllRoutes(projectRoot, routesDirOption, routeFileName, urlPath, metadataUrlPath));
244
+ regenerate();
245
+ },
246
+ configureServer(server) {
247
+ const onChange = (file) => {
248
+ if (normalizePath(file) === normalizePath(mcpEntry)) regenerate();
249
+ };
250
+ server.watcher.on("add", onChange);
251
+ server.watcher.on("change", onChange);
252
+ server.watcher.on("unlink", onChange);
253
+ server.watcher.once("close", () => {
254
+ server.watcher.off("add", onChange);
255
+ server.watcher.off("change", onChange);
256
+ server.watcher.off("unlink", onChange);
257
+ });
258
+ },
259
+ buildStart() {
260
+ regenerate();
261
+ }
262
+ };
323
263
  }
324
- var vite_default = mcpPlugin;
325
- export {
326
- assertMetadataPathShape,
327
- assertUrlPathShape,
328
- vite_default as default,
329
- deriveRouteFileName,
330
- mcpPlugin
331
- };
264
+ //#endregion
265
+ export { assertMetadataPathShape, assertUrlPathShape, mcpPlugin as default, mcpPlugin, deriveRouteFileName };