create-better-fullstack 1.7.0 → 1.8.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.
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-B_rZ4_sj.mjs";
2
+ import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-YcroedMK.mjs";
3
3
  import z from "zod";
4
- import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18nSchema, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LoggingSchema, OPTION_CATEGORY_METADATA, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
4
+ import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, ElixirApiSchema, ElixirAuthSchema, ElixirCachingSchema, ElixirDeploySchema, ElixirEmailSchema, ElixirHttpSchema, ElixirJobsSchema, ElixirJsonSchema, ElixirObservabilitySchema, ElixirOrmSchema, ElixirQualitySchema, ElixirRealtimeSchema, ElixirTestingSchema, ElixirValidationSchema, ElixirWebFrameworkSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18nSchema, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LoggingSchema, MobileDeepLinkingSchema, MobileNavigationSchema, MobileOTASchema, MobilePushSchema, MobileStorageSchema, MobileTestingSchema, MobileUISchema, OPTION_CATEGORY_METADATA, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonApiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
 
8
8
  //#region src/mcp.ts
9
- const INSTRUCTIONS = `Better-Fullstack scaffolds fullstack projects across TypeScript, Rust, Go, Python, and Java ecosystems with ${Object.values(OPTION_CATEGORY_METADATA).reduce((sum, metadata) => sum + metadata.options.length, 0)} configurable options.
9
+ const INSTRUCTIONS = `Better-Fullstack scaffolds fullstack projects across TypeScript, React Native, Rust, Go, Python, Java, and Elixir ecosystems with ${Object.values(OPTION_CATEGORY_METADATA).reduce((sum, metadata) => sum + metadata.options.length, 0)} configurable options.
10
10
 
11
11
  RECOMMENDED WORKFLOW:
12
12
  1. Call bfs_get_guidance to understand field semantics, required fields, and workflow rules.
@@ -24,7 +24,7 @@ CRITICAL RULES:
24
24
  - Array fields: "frontend", "addons", "examples", "aiDocs", "rustLibraries", "pythonAi", "javaLibraries", and "javaTestingLibraries". Most other option fields are strings.
25
25
  - "none" means "skip this feature entirely", not "use the default".
26
26
  - Always specify "ecosystem" first — it determines which other fields are relevant.
27
- - TypeScript-specific fields (frontend, backend, orm, etc.) are IGNORED for rust/python/go/java ecosystems.
27
+ - TypeScript web-specific fields (web frontend, backend, orm, etc.) are IGNORED for react-native/rust/python/go/java/elixir ecosystems.
28
28
  - The compatibility engine auto-adjusts invalid combinations — always call bfs_check_compatibility first to see adjustments.`;
29
29
  function getGuidance() {
30
30
  return {
@@ -37,38 +37,48 @@ function getGuidance() {
37
37
  "For existing projects: call bfs_plan_addition, then bfs_add_feature."
38
38
  ],
39
39
  ecosystems: {
40
- typescript: "Full-featured: frontend + backend + database + ORM + auth + payments + 20+ feature categories.",
40
+ typescript: "Full-featured web: frontend + backend + database + ORM + auth + payments + 20+ feature categories.",
41
+ "react-native": "Mobile: Expo/React Native frontend variants plus mobile navigation, UI, storage, testing, push, OTA, and deep linking.",
41
42
  rust: "Backend/CLI: web framework (axum/actix-web), ORM (sea-orm/sqlx), gRPC, GraphQL, CLI tools.",
42
43
  python: "Backend/AI: web framework (fastapi/django), ORM (sqlalchemy/sqlmodel), AI/ML integrations, task queues.",
43
44
  go: "Backend/CLI: web framework (gin/echo), ORM (gorm/sqlc), gRPC, CLI tools, logging.",
44
- java: "Backend/API: Spring Boot with Maven or Gradle Wrapper, optional Spring Data JPA, Spring Security, app libraries, and Java testing libraries."
45
+ java: "Backend/API: Spring Boot with Maven or Gradle Wrapper, optional Spring Data JPA, Spring Security, app libraries, and Java testing libraries.",
46
+ elixir: "Phoenix: Phoenix or Phoenix LiveView with Ecto SQL, PostgreSQL-ready config, REST or Absinthe, Channels/Presence, Oban, and Mix releases/Docker."
45
47
  },
46
48
  fieldRules: {
47
49
  projectName: "kebab-case directory name. Required for bfs_create_project.",
48
50
  ecosystem: "Must be set first. Determines which other fields are relevant.",
49
51
  frontend: "ARRAY of strings. TypeScript only. Supports multiple frontends in one monorepo. Use [] for API-only.",
50
52
  arrayFields: "Use arrays for frontend, addons, examples, aiDocs, rustLibraries, pythonAi, javaLibraries, and javaTestingLibraries. Use [] for \"none\" on multi-select fields.",
51
- backend: "String. \"self\" means fullstack mode (Next.js/TanStack Start/Nuxt/Astro API routes). \"none\" for frontend-only.",
53
+ backend: "String. \"self\" means fullstack mode (Next.js/Vinext/TanStack Start/Nuxt/Astro API routes). \"none\" for frontend-only.",
52
54
  runtime: "\"bun\" or \"node\". Must be \"none\" when backend is \"self\" or \"convex\".",
53
- addons: "ARRAY of strings. Monorepo tools, code quality, desktop (tauri), browser extensions (wxt), etc."
55
+ addons: "ARRAY of strings. Monorepo tools, code quality, desktop (tauri), browser extensions (wxt), etc.",
56
+ email: "String. TypeScript supports multiple providers; Rust, Python, Go, and Java currently support resend or none.",
57
+ observability: "String. TypeScript supports multiple providers; Rust, Python, Go, and Java currently support sentry or none.",
58
+ search: "String. TypeScript supports multiple providers; Rust, Python, Go, and Java currently support meilisearch or none."
54
59
  },
55
60
  ambiguityRules: [
56
61
  "If the user request leaves major stack choices unspecified, ASK the user before proceeding. Do not guess.",
57
62
  "Do not infer addons, examples, or optional features the user did not mention. Default strings to \"none\" and multi-select arrays to [].",
58
- "When the user says 'fullstack Next.js', use backend='self', frontend=['next'], runtime='none'.",
63
+ "When the user says 'fullstack Next.js', use backend='self', frontend=['next'], runtime='none'.\nWhen the user says 'fullstack Vinext', use backend='self', frontend=['vinext'], runtime='none'.",
59
64
  "When the user says 'React + Hono', use frontend=['tanstack-router'] (or ask which React framework), backend='hono'."
60
65
  ],
61
66
  criticalConstraints: [
62
- "tRPC (api='trpc') only works with React-based frontends: next, react-router, tanstack-router, tanstack-start.",
67
+ "tRPC (api='trpc') only works with React-based frontends: next, vinext, react-router, tanstack-router, tanstack-start.",
63
68
  "Use api='orpc' for svelte, solid, nuxt.",
64
69
  "Angular: use api='none' (has built-in HttpClient).",
65
70
  "Qwik: use backend='none', api='none' (built-in server).",
66
71
  "NestJS and AdonisJS backends require runtime='node'.",
67
72
  "Elysia backend requires runtime='bun'.",
68
- "backend='self' only works with: next, tanstack-start, astro, nuxt, svelte, solid-start.",
73
+ "backend='self' only works with: next, vinext, tanstack-start, astro, nuxt, svelte, solid-start.",
69
74
  "backend='convex' overrides: runtime=none, database=none, orm=none, api=none.",
70
75
  "TypeORM + better-auth: unsupported (no adapter). Use auth='none' or orm='drizzle'.",
71
- "Sequelize + better-auth: unsupported (no adapter). Use auth='none' or orm='drizzle'."
76
+ "Sequelize + better-auth: unsupported (no adapter). Use auth='none' or orm='drizzle'.",
77
+ "Non-TypeScript ecosystems only support email='resend' or email='none'.",
78
+ "Non-TypeScript ecosystems only support observability='sentry' or observability='none'.",
79
+ "Non-TypeScript ecosystems only support search='meilisearch' or search='none'.",
80
+ "Java email='resend' and observability='sentry' require javaBuildTool='maven' or javaBuildTool='gradle'.",
81
+ "Java search='meilisearch' requires javaBuildTool='maven' or javaBuildTool='gradle'."
72
82
  ]
73
83
  };
74
84
  }
@@ -104,6 +114,13 @@ const SCHEMA_MAP = {
104
114
  i18n: I18nSchema,
105
115
  search: SearchSchema,
106
116
  fileStorage: FileStorageSchema,
117
+ mobileNavigation: MobileNavigationSchema,
118
+ mobileUI: MobileUISchema,
119
+ mobileStorage: MobileStorageSchema,
120
+ mobileTesting: MobileTestingSchema,
121
+ mobilePush: MobilePushSchema,
122
+ mobileOTA: MobileOTASchema,
123
+ mobileDeepLinking: MobileDeepLinkingSchema,
107
124
  addons: AddonsSchema,
108
125
  examples: ExamplesSchema,
109
126
  packageManager: PackageManagerSchema,
@@ -126,6 +143,7 @@ const SCHEMA_MAP = {
126
143
  pythonValidation: PythonValidationSchema,
127
144
  pythonAi: PythonAiSchema,
128
145
  pythonAuth: PythonAuthSchema,
146
+ pythonApi: PythonApiSchema,
129
147
  pythonTaskQueue: PythonTaskQueueSchema,
130
148
  pythonGraphql: PythonGraphqlSchema,
131
149
  pythonQuality: PythonQualitySchema,
@@ -140,7 +158,22 @@ const SCHEMA_MAP = {
140
158
  javaOrm: JavaOrmSchema,
141
159
  javaAuth: JavaAuthSchema,
142
160
  javaLibraries: JavaLibrariesSchema,
143
- javaTestingLibraries: JavaTestingLibrariesSchema
161
+ javaTestingLibraries: JavaTestingLibrariesSchema,
162
+ elixirWebFramework: ElixirWebFrameworkSchema,
163
+ elixirOrm: ElixirOrmSchema,
164
+ elixirAuth: ElixirAuthSchema,
165
+ elixirApi: ElixirApiSchema,
166
+ elixirRealtime: ElixirRealtimeSchema,
167
+ elixirJobs: ElixirJobsSchema,
168
+ elixirValidation: ElixirValidationSchema,
169
+ elixirHttp: ElixirHttpSchema,
170
+ elixirJson: ElixirJsonSchema,
171
+ elixirEmail: ElixirEmailSchema,
172
+ elixirCaching: ElixirCachingSchema,
173
+ elixirObservability: ElixirObservabilitySchema,
174
+ elixirTesting: ElixirTestingSchema,
175
+ elixirQuality: ElixirQualitySchema,
176
+ elixirDeploy: ElixirDeploySchema
144
177
  };
145
178
  const ECOSYSTEM_CATEGORIES = {
146
179
  typescript: [
@@ -176,6 +209,17 @@ const ECOSYSTEM_CATEGORIES = {
176
209
  "fileStorage",
177
210
  "astroIntegration"
178
211
  ],
212
+ "react-native": [
213
+ "frontend",
214
+ "auth",
215
+ "mobileNavigation",
216
+ "mobileUI",
217
+ "mobileStorage",
218
+ "mobileTesting",
219
+ "mobilePush",
220
+ "mobileOTA",
221
+ "mobileDeepLinking"
222
+ ],
179
223
  rust: [
180
224
  "rustWebFramework",
181
225
  "rustFrontend",
@@ -186,7 +230,11 @@ const ECOSYSTEM_CATEGORIES = {
186
230
  "rustLogging",
187
231
  "rustErrorHandling",
188
232
  "rustCaching",
189
- "rustAuth"
233
+ "rustAuth",
234
+ "email",
235
+ "observability",
236
+ "caching",
237
+ "search"
190
238
  ],
191
239
  python: [
192
240
  "pythonWebFramework",
@@ -194,9 +242,14 @@ const ECOSYSTEM_CATEGORIES = {
194
242
  "pythonValidation",
195
243
  "pythonAi",
196
244
  "pythonAuth",
245
+ "pythonApi",
197
246
  "pythonTaskQueue",
198
247
  "pythonGraphql",
199
- "pythonQuality"
248
+ "pythonQuality",
249
+ "email",
250
+ "observability",
251
+ "caching",
252
+ "search"
200
253
  ],
201
254
  go: [
202
255
  "goWebFramework",
@@ -204,7 +257,12 @@ const ECOSYSTEM_CATEGORIES = {
204
257
  "goApi",
205
258
  "goCli",
206
259
  "goLogging",
207
- "goAuth"
260
+ "goAuth",
261
+ "auth",
262
+ "email",
263
+ "observability",
264
+ "caching",
265
+ "search"
208
266
  ],
209
267
  java: [
210
268
  "javaWebFramework",
@@ -212,7 +270,28 @@ const ECOSYSTEM_CATEGORIES = {
212
270
  "javaOrm",
213
271
  "javaAuth",
214
272
  "javaLibraries",
215
- "javaTestingLibraries"
273
+ "javaTestingLibraries",
274
+ "email",
275
+ "observability",
276
+ "caching",
277
+ "search"
278
+ ],
279
+ elixir: [
280
+ "elixirWebFramework",
281
+ "elixirOrm",
282
+ "elixirAuth",
283
+ "elixirApi",
284
+ "elixirRealtime",
285
+ "elixirJobs",
286
+ "elixirValidation",
287
+ "elixirHttp",
288
+ "elixirJson",
289
+ "elixirEmail",
290
+ "elixirCaching",
291
+ "elixirObservability",
292
+ "elixirTesting",
293
+ "elixirQuality",
294
+ "elixirDeploy"
216
295
  ],
217
296
  shared: [
218
297
  "ecosystem",
@@ -245,15 +324,21 @@ function getSchemaOptions(category, ecosystem) {
245
324
  }
246
325
  return result;
247
326
  }
248
- function getInstallCommand(ecosystem, projectName, packageManager, javaBuildTool) {
327
+ function getInstallCommand(ecosystem, projectName, packageManager, javaBuildTool, javaWebFramework) {
249
328
  switch (ecosystem) {
250
329
  case "rust": return `cd ${projectName} && cargo build`;
251
330
  case "python": return `cd ${projectName} && uv sync`;
252
331
  case "go": return `cd ${projectName} && go mod tidy`;
253
- case "java": return javaBuildTool === "gradle" ? `cd ${projectName} && ./gradlew test && ./gradlew bootRun` : `cd ${projectName} && ./mvnw test && ./mvnw spring-boot:run`;
332
+ case "elixir": return `cd ${projectName} && mix deps.get && mix compile && mix test`;
333
+ case "java":
334
+ if (javaWebFramework === "quarkus") return javaBuildTool === "gradle" ? `cd ${projectName} && ./gradlew test && ./gradlew quarkusDev` : `cd ${projectName} && ./mvnw test && ./mvnw quarkus:dev`;
335
+ return javaBuildTool === "gradle" ? `cd ${projectName} && ./gradlew test && ./gradlew bootRun` : `cd ${projectName} && ./mvnw test && ./mvnw spring-boot:run`;
254
336
  default: return `cd ${projectName} && ${packageManager ?? "bun"} install`;
255
337
  }
256
338
  }
339
+ function mcpInputSchema(schema) {
340
+ return schema;
341
+ }
257
342
  function filterCompatibilityResult(result, ecosystem) {
258
343
  const { adjustedStack, changes } = result;
259
344
  if (!adjustedStack) return {
@@ -277,14 +362,18 @@ function filterCompatibilityResult(result, ecosystem) {
277
362
  }
278
363
  function buildProjectConfig(input, overrides) {
279
364
  const projectName = input.projectName ?? "my-project";
365
+ const ecosystem = input.ecosystem ?? "typescript";
366
+ const frontend = input.frontend ?? (ecosystem === "react-native" ? ["native-bare"] : ["tanstack-router"]);
367
+ const hasNativeFrontend = frontend.some((item) => item.startsWith("native-"));
368
+ const hasMobileProject = ecosystem === "react-native" || hasNativeFrontend;
280
369
  return {
281
370
  projectName,
282
371
  projectDir: overrides?.projectDir ?? "/virtual",
283
372
  relativePath: overrides ? `./${projectName}` : "./virtual",
284
- ecosystem: input.ecosystem ?? "typescript",
285
- frontend: input.frontend ?? ["tanstack-router"],
286
- backend: input.backend ?? "hono",
287
- runtime: input.runtime ?? "bun",
373
+ ecosystem,
374
+ frontend,
375
+ backend: input.backend ?? (ecosystem === "react-native" ? "none" : "hono"),
376
+ runtime: input.runtime ?? (ecosystem === "react-native" ? "none" : "bun"),
288
377
  database: input.database ?? "none",
289
378
  orm: input.orm ?? "none",
290
379
  api: input.api ?? "none",
@@ -292,13 +381,13 @@ function buildProjectConfig(input, overrides) {
292
381
  payments: input.payments ?? "none",
293
382
  email: input.email ?? "none",
294
383
  fileUpload: input.fileUpload ?? "none",
295
- effect: "none",
384
+ effect: input.effect ?? "none",
296
385
  ai: input.ai ?? "none",
297
386
  stateManagement: input.stateManagement ?? "none",
298
387
  forms: input.forms ?? "none",
299
388
  validation: input.validation ?? "none",
300
389
  testing: input.testing ?? "none",
301
- cssFramework: input.cssFramework ?? "tailwind",
390
+ cssFramework: input.cssFramework ?? (ecosystem === "react-native" ? "none" : "tailwind"),
302
391
  uiLibrary: input.uiLibrary ?? "none",
303
392
  shadcnBase: "radix",
304
393
  shadcnStyle: "nova",
@@ -312,8 +401,15 @@ function buildProjectConfig(input, overrides) {
312
401
  animation: input.animation ?? "none",
313
402
  logging: input.logging ?? "none",
314
403
  observability: input.observability ?? "none",
315
- featureFlags: "none",
316
- analytics: "none",
404
+ featureFlags: input.featureFlags ?? "none",
405
+ analytics: input.analytics ?? "none",
406
+ mobileNavigation: input.mobileNavigation ?? (hasMobileProject ? "expo-router" : "none"),
407
+ mobileUI: input.mobileUI ?? "none",
408
+ mobileStorage: input.mobileStorage ?? "none",
409
+ mobileTesting: input.mobileTesting ?? "none",
410
+ mobilePush: input.mobilePush ?? "none",
411
+ mobileOTA: input.mobileOTA ?? "none",
412
+ mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
317
413
  cms: input.cms ?? "none",
318
414
  caching: input.caching ?? "none",
319
415
  i18n: input.i18n ?? "none",
@@ -345,6 +441,7 @@ function buildProjectConfig(input, overrides) {
345
441
  pythonValidation: input.pythonValidation ?? "none",
346
442
  pythonAi: input.pythonAi ?? [],
347
443
  pythonAuth: input.pythonAuth ?? "none",
444
+ pythonApi: input.pythonApi ?? "none",
348
445
  pythonTaskQueue: input.pythonTaskQueue ?? "none",
349
446
  pythonGraphql: input.pythonGraphql ?? "none",
350
447
  pythonQuality: input.pythonQuality ?? "none",
@@ -359,7 +456,22 @@ function buildProjectConfig(input, overrides) {
359
456
  javaOrm: input.javaOrm ?? "none",
360
457
  javaAuth: input.javaAuth ?? "none",
361
458
  javaLibraries: input.javaLibraries ?? [],
362
- javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"]
459
+ javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"],
460
+ elixirWebFramework: input.elixirWebFramework ?? "phoenix",
461
+ elixirOrm: input.elixirOrm ?? "ecto-sql",
462
+ elixirAuth: input.elixirAuth ?? "none",
463
+ elixirApi: input.elixirApi ?? "rest",
464
+ elixirRealtime: input.elixirRealtime ?? "channels",
465
+ elixirJobs: input.elixirJobs ?? "none",
466
+ elixirValidation: input.elixirValidation ?? "ecto-changesets",
467
+ elixirHttp: input.elixirHttp ?? "req",
468
+ elixirJson: input.elixirJson ?? "jason",
469
+ elixirEmail: input.elixirEmail ?? "none",
470
+ elixirCaching: input.elixirCaching ?? "none",
471
+ elixirObservability: input.elixirObservability ?? "telemetry",
472
+ elixirTesting: input.elixirTesting ?? "ex_unit",
473
+ elixirQuality: input.elixirQuality ?? "credo",
474
+ elixirDeploy: input.elixirDeploy ?? "none"
363
475
  };
364
476
  }
365
477
  function sanitizePath(input) {
@@ -369,7 +481,11 @@ function sanitizePath(input) {
369
481
  }
370
482
  function buildCompatibilityInput(input) {
371
483
  const frontend = input.frontend;
484
+ const webFrontend = (frontend ?? []).filter((item) => !item.startsWith("native-"));
485
+ const nativeFrontend = (frontend ?? []).filter((item) => item.startsWith("native-"));
372
486
  const addons = input.addons ?? [];
487
+ const ecosystem = input.ecosystem ?? "typescript";
488
+ const hasMobileProject = ecosystem === "react-native" || nativeFrontend.length > 0;
373
489
  const codeQuality = addons.filter((a) => [
374
490
  "biome",
375
491
  "oxlint",
@@ -385,10 +501,10 @@ function buildCompatibilityInput(input) {
385
501
  "none"
386
502
  ].includes(a));
387
503
  return {
388
- ecosystem: input.ecosystem ?? "typescript",
504
+ ecosystem,
389
505
  projectName: input.projectName ?? null,
390
- webFrontend: frontend ?? [],
391
- nativeFrontend: [],
506
+ webFrontend,
507
+ nativeFrontend,
392
508
  astroIntegration: input.astroIntegration ?? "none",
393
509
  runtime: input.runtime ?? "bun",
394
510
  backend: input.backend ?? "hono",
@@ -425,6 +541,13 @@ function buildCompatibilityInput(input) {
425
541
  cms: input.cms ?? "none",
426
542
  search: input.search ?? "none",
427
543
  fileStorage: input.fileStorage ?? "none",
544
+ mobileNavigation: input.mobileNavigation ?? (hasMobileProject ? "expo-router" : "none"),
545
+ mobileUI: input.mobileUI ?? "none",
546
+ mobileStorage: input.mobileStorage ?? "none",
547
+ mobileTesting: input.mobileTesting ?? "none",
548
+ mobilePush: input.mobilePush ?? "none",
549
+ mobileOTA: input.mobileOTA ?? "none",
550
+ mobileDeepLinking: input.mobileDeepLinking ?? (hasMobileProject ? "expo-linking" : "none"),
428
551
  codeQuality,
429
552
  documentation,
430
553
  appPlatforms,
@@ -454,6 +577,7 @@ function buildCompatibilityInput(input) {
454
577
  pythonValidation: input.pythonValidation ?? "none",
455
578
  pythonAi: input.pythonAi ?? [],
456
579
  pythonAuth: input.pythonAuth ?? "none",
580
+ pythonApi: input.pythonApi ?? "none",
457
581
  pythonTaskQueue: input.pythonTaskQueue ?? "none",
458
582
  pythonGraphql: input.pythonGraphql ?? "none",
459
583
  pythonQuality: input.pythonQuality ?? "none",
@@ -468,7 +592,22 @@ function buildCompatibilityInput(input) {
468
592
  javaOrm: input.javaOrm ?? "none",
469
593
  javaAuth: input.javaAuth ?? "none",
470
594
  javaLibraries: input.javaLibraries ?? [],
471
- javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"]
595
+ javaTestingLibraries: input.javaTestingLibraries ?? ["junit5"],
596
+ elixirWebFramework: input.elixirWebFramework ?? "phoenix",
597
+ elixirOrm: input.elixirOrm ?? "ecto-sql",
598
+ elixirAuth: input.elixirAuth ?? "none",
599
+ elixirApi: input.elixirApi ?? "rest",
600
+ elixirRealtime: input.elixirRealtime ?? "channels",
601
+ elixirJobs: input.elixirJobs ?? "none",
602
+ elixirValidation: input.elixirValidation ?? "ecto-changesets",
603
+ elixirHttp: input.elixirHttp ?? "req",
604
+ elixirJson: input.elixirJson ?? "jason",
605
+ elixirEmail: input.elixirEmail ?? "none",
606
+ elixirCaching: input.elixirCaching ?? "none",
607
+ elixirObservability: input.elixirObservability ?? "telemetry",
608
+ elixirTesting: input.elixirTesting ?? "ex_unit",
609
+ elixirQuality: input.elixirQuality ?? "credo",
610
+ elixirDeploy: input.elixirDeploy ?? "none"
472
611
  };
473
612
  }
474
613
  function summarizeTree(tree) {
@@ -492,7 +631,7 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
492
631
  ## Backend Constraints
493
632
  - **Convex**: Forces runtime=none, database=none, orm=none, api=none, dbSetup=none, serverDeploy=none. Removes incompatible frontends (Solid, SolidStart, Astro).
494
633
  - **No backend (none)**: Clears auth, payments, database, orm, api, serverDeploy, search, fileStorage.
495
- - **Fullstack (backend='self')**: Sets runtime=none, serverDeploy=none. Only works with: next, tanstack-start, astro, nuxt, svelte, solid-start.
634
+ - **Fullstack (backend='self')**: Sets runtime=none, serverDeploy=none. Only works with: next, vinext, tanstack-start, astro, nuxt, svelte, solid-start.
496
635
 
497
636
  ## Runtime Constraints
498
637
  - NestJS and AdonisJS require runtime=node.
@@ -501,7 +640,7 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
501
640
  - backend=self or backend=convex requires runtime=none.
502
641
 
503
642
  ## API Constraints
504
- - tRPC only works with React-based frontends: next, react-router, tanstack-router, tanstack-start.
643
+ - tRPC only works with React-based frontends: next, vinext, react-router, tanstack-router, tanstack-start.
505
644
  - Use oRPC for svelte, solid, nuxt.
506
645
  - Angular: use api=none (has built-in HttpClient).
507
646
  - Qwik: use backend=none, api=none (built-in server, no external APIs).
@@ -519,8 +658,16 @@ const COMPATIBILITY_RULES_MD = `# Better-Fullstack Compatibility Rules
519
658
  ## Payments
520
659
  - Polar requires better-auth and a web frontend.
521
660
 
661
+ ## Email
662
+ - Rust, Python, Go, and Java currently support only Resend for email (\`email=resend\`) or no email (\`email=none\`).
663
+ - Java Resend requires Maven or Gradle so the generated project can manage the SDK dependency.
664
+
665
+ ## Observability
666
+ - Rust, Python, Go, and Java currently support only Sentry for observability (\`observability=sentry\`) or no observability (\`observability=none\`).
667
+ - Java Sentry requires Maven or Gradle so the generated project can manage the SDK dependency.
668
+
522
669
  ## Ecosystem Isolation
523
- - Rust, Python, Go, and Java ecosystems are independent — TypeScript fields are ignored.
670
+ - Rust, Python, Go, Java, and Elixir ecosystems are independent — TypeScript fields are ignored.
524
671
  - Each ecosystem generates a standalone project with its own build system.
525
672
  `;
526
673
  const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
@@ -542,6 +689,8 @@ const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
542
689
  - ecosystem: "rust"
543
690
  - rustWebFramework: "axum"
544
691
  - rustOrm: "sqlx"
692
+ - email: "resend" (optional)
693
+ - observability: "sentry" (optional)
545
694
  2. Tell the user to run: cd my-rust-app && cargo build
546
695
 
547
696
  ## Quick Start — Python Project
@@ -550,6 +699,8 @@ const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
550
699
  - ecosystem: "python"
551
700
  - pythonWebFramework: "fastapi"
552
701
  - pythonOrm: "sqlalchemy"
702
+ - email: "resend" (optional)
703
+ - observability: "sentry" (optional)
553
704
  2. Tell the user to run: cd my-python-app && uv sync
554
705
 
555
706
  ## Quick Start — Go Project
@@ -558,6 +709,8 @@ const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
558
709
  - ecosystem: "go"
559
710
  - goWebFramework: "gin"
560
711
  - goOrm: "gorm"
712
+ - email: "resend" (optional)
713
+ - observability: "sentry" (optional)
561
714
  2. Tell the user to run: cd my-go-app && go mod tidy && go run cmd/server/main.go
562
715
 
563
716
  ## Quick Start — Java Project
@@ -566,11 +719,14 @@ const GETTING_STARTED_MD = `# Getting Started with Better-Fullstack MCP
566
719
  - ecosystem: "java"
567
720
  - javaWebFramework: "spring-boot"
568
721
  - javaBuildTool: "maven"
722
+ - email: "resend" (optional)
723
+ - observability: "sentry" (optional)
569
724
  2. Tell the user to run: cd my-java-app && ./mvnw test && ./mvnw spring-boot:run
570
725
 
571
726
  ## Adding Features to Existing Projects
572
727
  1. Call bfs_add_feature with projectDir pointing to the project root.
573
728
  2. Provide addons array with features to add (e.g., ["biome", "turborepo"]).
729
+ 3. Service categories such as email and observability are scaffold-time options. To add those to an existing app, inspect the generated templates from bfs_plan_project and apply the equivalent dependency, env var, and initialization changes manually.
574
730
  `;
575
731
  async function startMcpServer() {
576
732
  const server = new McpServer({
@@ -580,24 +736,25 @@ async function startMcpServer() {
580
736
  instructions: INSTRUCTIONS,
581
737
  capabilities: { logging: {} }
582
738
  });
583
- server.tool("bfs_get_guidance", "Returns workflow rules, field semantics, ambiguity rules, and critical constraints. Call this FIRST before using other tools.", {}, async () => {
739
+ const registerTool = server.tool.bind(server);
740
+ registerTool("bfs_get_guidance", "Returns workflow rules, field semantics, ambiguity rules, and critical constraints. Call this FIRST before using other tools.", mcpInputSchema({}), async () => {
584
741
  const guidance = getGuidance();
585
742
  return { content: [{
586
743
  type: "text",
587
744
  text: JSON.stringify(guidance, null, 2)
588
745
  }] };
589
746
  });
590
- server.tool("bfs_get_schema", "Returns valid options for a specific category (e.g., 'database', 'frontend', 'backend') or ALL categories. Use ecosystem to filter to relevant categories only.", {
747
+ registerTool("bfs_get_schema", "Returns valid options for a specific category (e.g., 'database', 'frontend', 'backend') or ALL categories. Use ecosystem to filter to relevant categories only.", mcpInputSchema({
591
748
  category: z.string().optional().describe("Category name (e.g., 'database', 'orm', 'frontend'). Omit for all categories."),
592
749
  ecosystem: EcosystemSchema.optional().describe("Filter categories to this ecosystem (e.g., 'rust' returns only Rust + shared categories).")
593
- }, async ({ category, ecosystem }) => {
750
+ }), async ({ category, ecosystem }) => {
594
751
  const result = getSchemaOptions(category, ecosystem);
595
752
  return { content: [{
596
753
  type: "text",
597
754
  text: JSON.stringify(result, null, 2)
598
755
  }] };
599
756
  });
600
- server.tool("bfs_check_compatibility", "Validates a stack combination and returns auto-adjusted selections with warnings. Call BEFORE creating a project to avoid invalid combinations.", {
757
+ registerTool("bfs_check_compatibility", "Validates a stack combination and returns auto-adjusted selections with warnings. Call BEFORE creating a project to avoid invalid combinations.", mcpInputSchema({
601
758
  ecosystem: EcosystemSchema.describe("Language ecosystem"),
602
759
  frontend: z.array(z.string()).optional().describe("Web frontend frameworks (TypeScript only)"),
603
760
  backend: z.string().optional().describe("Backend framework"),
@@ -607,16 +764,88 @@ async function startMcpServer() {
607
764
  api: z.string().optional().describe("API layer"),
608
765
  auth: z.string().optional().describe("Auth provider"),
609
766
  payments: z.string().optional().describe("Payments provider"),
767
+ email: EmailSchema.optional().describe("Email provider"),
768
+ fileUpload: FileUploadSchema.optional().describe("File upload provider"),
769
+ ai: AISchema.optional().describe("AI SDK"),
770
+ stateManagement: StateManagementSchema.optional().describe("State management"),
771
+ forms: FormsSchema.optional().describe("Forms library"),
772
+ validation: ValidationSchema.optional().describe("Validation library"),
773
+ testing: TestingSchema.optional().describe("Testing framework"),
774
+ realtime: RealtimeSchema.optional().describe("Realtime library"),
775
+ jobQueue: JobQueueSchema.optional().describe("Job queue"),
776
+ animation: AnimationSchema.optional().describe("Animation library"),
777
+ logging: LoggingSchema.optional().describe("Logging library"),
778
+ observability: ObservabilitySchema.optional().describe("Observability provider"),
779
+ featureFlags: FeatureFlagsSchema.optional().describe("Feature flags provider"),
780
+ analytics: AnalyticsSchema.optional().describe("Analytics provider"),
781
+ cms: CMSSchema.optional().describe("CMS"),
782
+ caching: CachingSchema.optional().describe("Caching solution"),
783
+ i18n: I18nSchema.optional().describe("Internationalization library"),
784
+ search: SearchSchema.optional().describe("Search engine"),
785
+ fileStorage: FileStorageSchema.optional().describe("File storage"),
786
+ mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
787
+ mobileUI: MobileUISchema.optional().describe("Mobile UI"),
788
+ mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
789
+ mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
790
+ mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
791
+ mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
792
+ mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
793
+ dbSetup: DatabaseSetupSchema.optional().describe("Database hosting provider"),
794
+ webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
795
+ serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
796
+ astroIntegration: AstroIntegrationSchema.optional().describe("Astro UI framework integration"),
610
797
  uiLibrary: z.string().optional().describe("UI component library"),
611
798
  cssFramework: z.string().optional().describe("CSS framework"),
612
- addons: z.array(z.string()).optional().describe("Addon list"),
799
+ addons: z.array(AddonsSchema).optional().describe("Addon list"),
800
+ examples: z.array(ExamplesSchema).optional().describe("Example templates"),
801
+ packageManager: PackageManagerSchema.optional().describe("Package manager"),
802
+ rustWebFramework: RustWebFrameworkSchema.optional().describe("Rust web framework"),
803
+ rustFrontend: RustFrontendSchema.optional().describe("Rust frontend (WASM)"),
804
+ rustOrm: RustOrmSchema.optional().describe("Rust ORM"),
805
+ rustApi: RustApiSchema.optional().describe("Rust API layer"),
806
+ rustCli: RustCliSchema.optional().describe("Rust CLI framework"),
807
+ rustLibraries: z.array(RustLibrariesSchema).optional().describe("Rust libraries"),
808
+ rustLogging: RustLoggingSchema.optional().describe("Rust logging library"),
809
+ rustErrorHandling: RustErrorHandlingSchema.optional().describe("Rust error handling library"),
810
+ rustCaching: RustCachingSchema.optional().describe("Rust caching library"),
811
+ rustAuth: RustAuthSchema.optional().describe("Rust authentication library"),
812
+ pythonWebFramework: PythonWebFrameworkSchema.optional().describe("Python web framework"),
813
+ pythonOrm: PythonOrmSchema.optional().describe("Python ORM"),
814
+ pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
815
+ pythonAi: z.array(PythonAiSchema).optional().describe("Python AI libraries"),
816
+ pythonAuth: PythonAuthSchema.optional().describe("Python auth library"),
817
+ pythonApi: PythonApiSchema.optional().describe("Python API framework"),
818
+ pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue"),
819
+ pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL framework"),
820
+ pythonQuality: PythonQualitySchema.optional().describe("Python code quality"),
821
+ goWebFramework: GoWebFrameworkSchema.optional().describe("Go web framework"),
822
+ goOrm: GoOrmSchema.optional().describe("Go ORM"),
823
+ goApi: GoApiSchema.optional().describe("Go API layer"),
824
+ goCli: GoCliSchema.optional().describe("Go CLI framework"),
825
+ goLogging: GoLoggingSchema.optional().describe("Go logging library"),
826
+ goAuth: GoAuthSchema.optional().describe("Go authentication library"),
613
827
  javaWebFramework: JavaWebFrameworkSchema.optional().describe("Java web framework"),
614
828
  javaBuildTool: JavaBuildToolSchema.optional().describe("Java build tool"),
615
829
  javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
616
830
  javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
617
831
  javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
618
- javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries")
619
- }, async (input) => {
832
+ javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
833
+ elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
834
+ elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
835
+ elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
836
+ elixirApi: ElixirApiSchema.optional().describe("Elixir API layer"),
837
+ elixirRealtime: ElixirRealtimeSchema.optional().describe("Elixir realtime feature"),
838
+ elixirJobs: ElixirJobsSchema.optional().describe("Elixir jobs and scheduling"),
839
+ elixirValidation: ElixirValidationSchema.optional().describe("Elixir validation/data"),
840
+ elixirHttp: ElixirHttpSchema.optional().describe("Elixir HTTP client"),
841
+ elixirJson: ElixirJsonSchema.optional().describe("Elixir JSON library"),
842
+ elixirEmail: ElixirEmailSchema.optional().describe("Elixir email library"),
843
+ elixirCaching: ElixirCachingSchema.optional().describe("Elixir caching library"),
844
+ elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
845
+ elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
846
+ elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
847
+ elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
848
+ }), async (input) => {
620
849
  try {
621
850
  const filtered = filterCompatibilityResult(analyzeStackCompatibility(buildCompatibilityInput(input)), input.ecosystem);
622
851
  return { content: [{
@@ -660,11 +889,19 @@ async function startMcpServer() {
660
889
  animation: AnimationSchema.optional().describe("Animation library"),
661
890
  logging: LoggingSchema.optional().describe("Logging library"),
662
891
  observability: ObservabilitySchema.optional().describe("Observability"),
892
+ featureFlags: FeatureFlagsSchema.optional().describe("Feature flag provider"),
663
893
  search: SearchSchema.optional().describe("Search engine"),
664
894
  caching: CachingSchema.optional().describe("Caching solution"),
665
895
  i18n: I18nSchema.optional().describe("Internationalization (i18n) library"),
666
896
  cms: CMSSchema.optional().describe("CMS"),
667
897
  fileStorage: FileStorageSchema.optional().describe("File storage"),
898
+ mobileNavigation: MobileNavigationSchema.optional().describe("Mobile navigation"),
899
+ mobileUI: MobileUISchema.optional().describe("Mobile UI"),
900
+ mobileStorage: MobileStorageSchema.optional().describe("Mobile storage"),
901
+ mobileTesting: MobileTestingSchema.optional().describe("Mobile testing"),
902
+ mobilePush: MobilePushSchema.optional().describe("Mobile push notifications"),
903
+ mobileOTA: MobileOTASchema.optional().describe("Mobile OTA updates"),
904
+ mobileDeepLinking: MobileDeepLinkingSchema.optional().describe("Mobile deep linking"),
668
905
  fileUpload: FileUploadSchema.optional().describe("File upload"),
669
906
  webDeploy: WebDeploySchema.optional().describe("Web deployment target"),
670
907
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment target"),
@@ -684,7 +921,9 @@ async function startMcpServer() {
684
921
  pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
685
922
  pythonAi: z.array(PythonAiSchema).optional().describe("Python AI libraries"),
686
923
  pythonAuth: PythonAuthSchema.optional().describe("Python auth library"),
924
+ pythonApi: PythonApiSchema.optional().describe("Python API framework"),
687
925
  pythonTaskQueue: PythonTaskQueueSchema.optional().describe("Python task queue"),
926
+ pythonGraphql: PythonGraphqlSchema.optional().describe("Python GraphQL framework"),
688
927
  pythonQuality: PythonQualitySchema.optional().describe("Python code quality"),
689
928
  goWebFramework: GoWebFrameworkSchema.optional().describe("Go web framework"),
690
929
  goOrm: GoOrmSchema.optional().describe("Go ORM"),
@@ -697,9 +936,24 @@ async function startMcpServer() {
697
936
  javaOrm: JavaOrmSchema.optional().describe("Java ORM"),
698
937
  javaAuth: JavaAuthSchema.optional().describe("Java authentication library"),
699
938
  javaLibraries: z.array(JavaLibrariesSchema).optional().describe("Java application libraries"),
700
- javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries")
939
+ javaTestingLibraries: z.array(JavaTestingLibrariesSchema).optional().describe("Java testing libraries"),
940
+ elixirWebFramework: ElixirWebFrameworkSchema.optional().describe("Elixir web framework"),
941
+ elixirOrm: ElixirOrmSchema.optional().describe("Elixir persistence layer"),
942
+ elixirAuth: ElixirAuthSchema.optional().describe("Elixir authentication"),
943
+ elixirApi: ElixirApiSchema.optional().describe("Elixir API layer"),
944
+ elixirRealtime: ElixirRealtimeSchema.optional().describe("Elixir realtime feature"),
945
+ elixirJobs: ElixirJobsSchema.optional().describe("Elixir jobs and scheduling"),
946
+ elixirValidation: ElixirValidationSchema.optional().describe("Elixir validation/data"),
947
+ elixirHttp: ElixirHttpSchema.optional().describe("Elixir HTTP client"),
948
+ elixirJson: ElixirJsonSchema.optional().describe("Elixir JSON library"),
949
+ elixirEmail: ElixirEmailSchema.optional().describe("Elixir email library"),
950
+ elixirCaching: ElixirCachingSchema.optional().describe("Elixir caching library"),
951
+ elixirObservability: ElixirObservabilitySchema.optional().describe("Elixir observability"),
952
+ elixirTesting: ElixirTestingSchema.optional().describe("Elixir testing library"),
953
+ elixirQuality: ElixirQualitySchema.optional().describe("Elixir code quality/security"),
954
+ elixirDeploy: ElixirDeploySchema.optional().describe("Elixir deployment target")
701
955
  };
702
- server.tool("bfs_plan_project", "Dry-run: generates a project in-memory and returns the file tree WITHOUT writing to disk. Use this to preview what would be created.", planCreateSchema, async (input) => {
956
+ registerTool("bfs_plan_project", "Dry-run: generates a project in-memory and returns the file tree WITHOUT writing to disk. Use this to preview what would be created.", mcpInputSchema(planCreateSchema), async (input) => {
703
957
  try {
704
958
  const { generateVirtualProject, EMBEDDED_TEMPLATES } = await import("@better-fullstack/template-generator");
705
959
  const result = await generateVirtualProject({
@@ -736,10 +990,10 @@ async function startMcpServer() {
736
990
  };
737
991
  }
738
992
  });
739
- server.tool("bfs_create_project", "Creates a new fullstack project on disk. Dependencies are NOT installed (agent must tell user to install manually). Call bfs_plan_project first to preview.", {
993
+ registerTool("bfs_create_project", "Creates a new fullstack project on disk. Dependencies are NOT installed (agent must tell user to install manually). Call bfs_plan_project first to preview.", mcpInputSchema({
740
994
  ...planCreateSchema,
741
995
  projectName: z.string().describe("Project name (kebab-case). Will be the directory name.")
742
- }, async (input) => {
996
+ }), async (input) => {
743
997
  try {
744
998
  const { generateVirtualProject, EMBEDDED_TEMPLATES } = await import("@better-fullstack/template-generator");
745
999
  const { writeTreeToFilesystem } = await import("@better-fullstack/template-generator/fs-writer");
@@ -766,10 +1020,10 @@ async function startMcpServer() {
766
1020
  await writeBtsConfig(config);
767
1021
  let addonWarnings = [];
768
1022
  if (config.addons.length > 0 && config.addons[0] !== "none") {
769
- const { setupAddons } = await import("./addons-setup-CBK1Htlc.mjs");
1023
+ const { setupAddons } = await import("./addons-setup-CJwQAWFg.mjs");
770
1024
  addonWarnings = await setupAddons(config);
771
1025
  }
772
- const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager, input.javaBuildTool);
1026
+ const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager, input.javaBuildTool, input.javaWebFramework);
773
1027
  return { content: [{
774
1028
  type: "text",
775
1029
  text: JSON.stringify({
@@ -790,12 +1044,12 @@ async function startMcpServer() {
790
1044
  };
791
1045
  }
792
1046
  });
793
- server.tool("bfs_plan_addition", "Validates what would be added to an existing project. Reads the project config (bts.jsonc) and checks which addons are new.", {
1047
+ registerTool("bfs_plan_addition", "Validates what would be added to an existing project. Reads the project config (bts.jsonc) and checks which addons are new.", mcpInputSchema({
794
1048
  projectDir: z.string().describe("Absolute path to the existing project directory"),
795
1049
  addons: z.array(AddonsSchema).optional().describe("Addons to add"),
796
1050
  webDeploy: WebDeploySchema.optional().describe("Web deployment option"),
797
1051
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment option")
798
- }, async ({ projectDir, addons, webDeploy, serverDeploy }) => {
1052
+ }), async ({ projectDir, addons, webDeploy, serverDeploy }) => {
799
1053
  try {
800
1054
  const safePath = sanitizePath(projectDir);
801
1055
  const config = await readBtsConfig(safePath);
@@ -848,13 +1102,13 @@ async function startMcpServer() {
848
1102
  };
849
1103
  }
850
1104
  });
851
- server.tool("bfs_add_feature", "Adds addons/features to an existing Better-Fullstack project. Dependencies are NOT installed. Call bfs_plan_addition first to validate.", {
1105
+ registerTool("bfs_add_feature", "Adds addons/features to an existing Better-Fullstack project. Dependencies are NOT installed. Call bfs_plan_addition first to validate.", mcpInputSchema({
852
1106
  projectDir: z.string().describe("Absolute path to the existing project directory"),
853
1107
  addons: z.array(AddonsSchema).optional().describe("Addons to add"),
854
1108
  webDeploy: WebDeploySchema.optional().describe("Web deployment option"),
855
1109
  serverDeploy: ServerDeploySchema.optional().describe("Server deployment option"),
856
1110
  packageManager: PackageManagerSchema.optional().describe("Package manager to use")
857
- }, async (input) => {
1111
+ }), async (input) => {
858
1112
  try {
859
1113
  const safePath = sanitizePath(input.projectDir);
860
1114
  const { add } = await import("./index.mjs");
@@ -868,7 +1122,7 @@ async function startMcpServer() {
868
1122
  });
869
1123
  if (result?.success) {
870
1124
  const existingConfig = await readBtsConfig(safePath);
871
- const installCmd = getInstallCommand(existingConfig?.ecosystem ?? "typescript", safePath.split("/").pop() ?? "project", input.packageManager, existingConfig?.javaBuildTool);
1125
+ const installCmd = getInstallCommand(existingConfig?.ecosystem ?? "typescript", safePath.split("/").pop() ?? "project", input.packageManager, existingConfig?.javaBuildTool, existingConfig?.javaWebFramework);
872
1126
  return { content: [{
873
1127
  type: "text",
874
1128
  text: JSON.stringify({