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.
- package/README.md +2 -2
- package/dist/addons-setup-CJwQAWFg.mjs +5 -0
- package/dist/{addons-setup-DQa6TRrx.mjs → addons-setup-CUmA_nra.mjs} +5 -5
- package/dist/{bts-config-B_rZ4_sj.mjs → bts-config-YcroedMK.mjs} +48 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +333 -64
- package/dist/index.mjs +1539 -133
- package/dist/{mcp-CuEEG8e5.mjs → mcp-DoPutOIG.mjs} +1 -1
- package/dist/mcp-entry.mjs +307 -53
- package/package.json +11 -11
- package/dist/addons-setup-CBK1Htlc.mjs +0 -5
package/dist/mcp-entry.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-
|
|
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
|
|
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 "
|
|
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
|
|
285
|
-
frontend
|
|
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
|
|
504
|
+
ecosystem,
|
|
389
505
|
projectName: input.projectName ?? null,
|
|
390
|
-
webFrontend
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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({
|