@agiflowai/scaffold-mcp 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +54 -11
  2. package/dist/index.js +391 -54
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -154,15 +154,32 @@ Use scaffold-mcp as a standalone CLI tool for template management and scaffoldin
154
154
  #### Template Management
155
155
 
156
156
  ```bash
157
- # Initialize templates folder
157
+ # Initialize templates folder and auto-download official templates
158
158
  scaffold-mcp init
159
- scaffold-mcp init --path /path/to/templates
160
159
 
161
- # Add templates from repositories
160
+ # Initialize at custom path
161
+ scaffold-mcp init --path ./custom-templates
162
+
163
+ # Initialize without downloading templates
164
+ scaffold-mcp init --no-download
165
+
166
+ # Add templates from repositories (full or subdirectory)
162
167
  scaffold-mcp add --name my-template --url https://github.com/user/template
163
- scaffold-mcp add --name my-scaffold --url https://github.com/user/scaffold --type scaffold
168
+ scaffold-mcp add --name nextjs-custom --url https://github.com/user/repo/tree/main/templates/nextjs
164
169
  ```
165
170
 
171
+ **What `init` does:**
172
+ 1. Creates `templates/` folder in your workspace root
173
+ 2. Automatically downloads official templates from [AgiFlow/aicode-toolkit](https://github.com/AgiFlow/aicode-toolkit/tree/main/templates)
174
+ 3. Creates a README.md with usage instructions
175
+ 4. Skips templates that already exist (safe to re-run)
176
+
177
+ **What `add` does:**
178
+ 1. Parses GitHub URL to detect full repository vs subdirectory
179
+ 2. Downloads template using git clone (full repo) or sparse checkout (subdirectory)
180
+ 3. Validates template has required configuration files (scaffold.yaml)
181
+ 4. Saves template to your templates folder
182
+
166
183
  #### Boilerplate Commands
167
184
 
168
185
  ```bash
@@ -205,24 +222,50 @@ scaffold-mcp scaffold add scaffold-nextjs-page \
205
222
 
206
223
  ### 1. Initialize Templates
207
224
 
225
+ The `init` command sets up your templates folder and **automatically downloads official templates** from the AgiFlow repository:
226
+
208
227
  ```bash
209
- # Initialize templates folder in your project
228
+ # Initialize templates folder and download official templates
210
229
  scaffold-mcp init
211
230
 
212
231
  # Or specify a custom path
213
232
  scaffold-mcp init --path ./my-templates
233
+
234
+ # Skip auto-download if you want to add templates manually
235
+ scaffold-mcp init --no-download
214
236
  ```
215
237
 
216
- ### 2. Add Templates
238
+ **What gets downloaded:**
239
+ - ✅ `nextjs-15-drizzle` - Next.js 15 with App Router, TypeScript, Tailwind CSS 4, Storybook, and optional Drizzle ORM
240
+ - ✅ More templates coming soon...
217
241
 
218
- ```bash
219
- # Add a boilerplate template from a repository
220
- scaffold-mcp add --name nextjs-15 --url https://github.com/yourorg/nextjs-15-template
242
+ All templates from [github.com/AgiFlow/aicode-toolkit/templates](https://github.com/AgiFlow/aicode-toolkit/tree/main/templates) are automatically pulled into your workspace.
243
+
244
+ ### 2. Add Custom Templates
245
+
246
+ Add additional templates from GitHub repositories or subdirectories:
221
247
 
222
- # Add a scaffold template
223
- scaffold-mcp add --name react-component --url https://github.com/yourorg/react-component-scaffold --type scaffold
248
+ ```bash
249
+ # Add a template from a full repository
250
+ scaffold-mcp add --name my-template --url https://github.com/yourorg/nextjs-template
251
+
252
+ # Add a template from a repository subdirectory (NEW!)
253
+ scaffold-mcp add \
254
+ --name nextjs-15-drizzle \
255
+ --url https://github.com/AgiFlow/aicode-toolkit/tree/main/templates/nextjs-15-drizzle
256
+
257
+ # Add to a specific type folder
258
+ scaffold-mcp add \
259
+ --name react-component \
260
+ --url https://github.com/yourorg/react-component-scaffold \
261
+ --type scaffold
224
262
  ```
225
263
 
264
+ **Supported URL formats:**
265
+ - Full repository: `https://github.com/user/repo`
266
+ - Subdirectory: `https://github.com/user/repo/tree/branch/path/to/template`
267
+ - With `.git` extension: `https://github.com/user/repo.git`
268
+
226
269
  ### 3. Create a New Project
227
270
 
228
271
  ```bash
package/dist/index.js CHANGED
@@ -4,13 +4,13 @@ import { ScaffoldConfigLoader } from "./ScaffoldConfigLoader-CI0T6zdG.js";
4
4
  import { TemplateService } from "./TemplateService-CnxvhRVW.js";
5
5
  import { VariableReplacementService } from "./VariableReplacementService-Bq0GDhTo.js";
6
6
  import { Command } from "commander";
7
- import { exec } from "node:child_process";
8
7
  import * as path$1 from "node:path";
9
8
  import path from "node:path";
10
- import { promisify } from "node:util";
11
9
  import * as fs$1 from "fs-extra";
12
10
  import fs from "fs-extra";
13
11
  import chalk from "chalk";
12
+ import { exec } from "node:child_process";
13
+ import { promisify } from "node:util";
14
14
  import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
15
15
  import * as yaml$1 from "js-yaml";
16
16
  import yaml from "js-yaml";
@@ -82,7 +82,8 @@ const icons = {
82
82
  download: "=�",
83
83
  upload: "=�",
84
84
  gear: "�",
85
- clipboard: "=�"
85
+ clipboard: "=�",
86
+ skip: "⏭"
86
87
  };
87
88
  /**
88
89
  * Themed message helpers
@@ -136,9 +137,92 @@ const sections = {
136
137
  };
137
138
 
138
139
  //#endregion
139
- //#region src/cli/add.ts
140
+ //#region src/utils/git.ts
140
141
  const execAsync = promisify(exec);
141
142
  /**
143
+ * Parse GitHub URL to detect if it's a subdirectory
144
+ * Supports formats:
145
+ * - https://github.com/user/repo
146
+ * - https://github.com/user/repo/tree/branch/path/to/dir
147
+ * - https://github.com/user/repo/tree/main/path/to/dir
148
+ */
149
+ function parseGitHubUrl(url) {
150
+ const treeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
151
+ const blobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
152
+ const rootMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
153
+ if (treeMatch || blobMatch) {
154
+ const match = treeMatch || blobMatch;
155
+ return {
156
+ owner: match[1],
157
+ repo: match[2],
158
+ repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
159
+ branch: match[3],
160
+ subdirectory: match[4],
161
+ isSubdirectory: true
162
+ };
163
+ }
164
+ if (rootMatch) return {
165
+ owner: rootMatch[1],
166
+ repo: rootMatch[2],
167
+ repoUrl: `https://github.com/${rootMatch[1]}/${rootMatch[2]}.git`,
168
+ isSubdirectory: false
169
+ };
170
+ return {
171
+ repoUrl: url,
172
+ isSubdirectory: false
173
+ };
174
+ }
175
+ /**
176
+ * Clone a subdirectory from a git repository using sparse checkout
177
+ */
178
+ async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
179
+ const tempFolder = `${targetFolder}.tmp`;
180
+ try {
181
+ await execAsync(`git init "${tempFolder}"`);
182
+ await execAsync(`git -C "${tempFolder}" remote add origin ${repoUrl}`);
183
+ await execAsync(`git -C "${tempFolder}" config core.sparseCheckout true`);
184
+ const sparseCheckoutFile = path.join(tempFolder, ".git", "info", "sparse-checkout");
185
+ await fs$1.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
186
+ await execAsync(`git -C "${tempFolder}" pull --depth=1 origin ${branch}`);
187
+ const sourceDir = path.join(tempFolder, subdirectory);
188
+ if (!await fs$1.pathExists(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
189
+ await fs$1.move(sourceDir, targetFolder);
190
+ await fs$1.remove(tempFolder);
191
+ } catch (error) {
192
+ if (await fs$1.pathExists(tempFolder)) await fs$1.remove(tempFolder);
193
+ throw error;
194
+ }
195
+ }
196
+ /**
197
+ * Clone entire repository
198
+ */
199
+ async function cloneRepository(repoUrl, targetFolder) {
200
+ await execAsync(`git clone ${repoUrl} "${targetFolder}"`);
201
+ const gitFolder = path.join(targetFolder, ".git");
202
+ if (await fs$1.pathExists(gitFolder)) await fs$1.remove(gitFolder);
203
+ }
204
+ /**
205
+ * Fetch directory listing from GitHub API
206
+ */
207
+ async function fetchGitHubDirectoryContents(owner, repo, path$2, branch = "main") {
208
+ const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$2}?ref=${branch}`;
209
+ const response = await fetch(url, { headers: {
210
+ Accept: "application/vnd.github.v3+json",
211
+ "User-Agent": "scaffold-mcp"
212
+ } });
213
+ if (!response.ok) throw new Error(`Failed to fetch directory contents: ${response.statusText}`);
214
+ const data = await response.json();
215
+ if (!Array.isArray(data)) throw new Error("Expected directory but got file");
216
+ return data.map((item) => ({
217
+ name: item.name,
218
+ type: item.type,
219
+ path: item.path
220
+ }));
221
+ }
222
+
223
+ //#endregion
224
+ //#region src/cli/add.ts
225
+ /**
142
226
  * Add command - add a template to templates folder
143
227
  */
144
228
  const addCommand = new Command("add").description("Add a template to templates folder").requiredOption("--name <name>", "Template name").requiredOption("--url <url>", "URL of the template repository to download").option("--path <path>", "Path to templates folder", "./templates").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
@@ -158,10 +242,12 @@ const addCommand = new Command("add").description("Add a template to templates f
158
242
  }
159
243
  logger.info(`${icons.download} Downloading template '${templateName}' from ${templateUrl}...`);
160
244
  await fs$1.ensureDir(path.dirname(targetFolder));
245
+ const parsedUrl = parseGitHubUrl(templateUrl);
161
246
  try {
162
- await execAsync(`git clone ${templateUrl} "${targetFolder}"`);
163
- const gitFolder = path.join(targetFolder, ".git");
164
- if (await fs$1.pathExists(gitFolder)) await fs$1.remove(gitFolder);
247
+ if (parsedUrl.isSubdirectory && parsedUrl.branch && parsedUrl.subdirectory) {
248
+ logger.info(`${icons.folder} Detected subdirectory: ${parsedUrl.subdirectory} (branch: ${parsedUrl.branch})`);
249
+ await cloneSubdirectory(parsedUrl.repoUrl, parsedUrl.branch, parsedUrl.subdirectory, targetFolder);
250
+ } else await cloneRepository(parsedUrl.repoUrl, targetFolder);
165
251
  messages.success(`Template '${templateName}' added successfully!`);
166
252
  logger.header(`\n${icons.folder} Template location:`);
167
253
  logger.indent(targetFolder);
@@ -531,27 +617,60 @@ async function findWorkspaceRoot(startPath = process.cwd()) {
531
617
  currentPath = path.dirname(currentPath);
532
618
  }
533
619
  }
620
+ const DEFAULT_TEMPLATE_REPO = {
621
+ owner: "AgiFlow",
622
+ repo: "aicode-toolkit",
623
+ branch: "main",
624
+ path: "templates"
625
+ };
626
+ /**
627
+ * Download templates from GitHub repository
628
+ */
629
+ async function downloadTemplates(templatesPath) {
630
+ try {
631
+ logger.info(`${icons.download} Fetching templates from ${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}...`);
632
+ const templateDirs = (await fetchGitHubDirectoryContents(DEFAULT_TEMPLATE_REPO.owner, DEFAULT_TEMPLATE_REPO.repo, DEFAULT_TEMPLATE_REPO.path, DEFAULT_TEMPLATE_REPO.branch)).filter((item) => item.type === "dir");
633
+ if (templateDirs.length === 0) {
634
+ messages.warning("No templates found in repository");
635
+ return;
636
+ }
637
+ logger.info(`${icons.folder} Found ${templateDirs.length} template(s)`);
638
+ for (const template of templateDirs) {
639
+ const targetFolder = path.join(templatesPath, template.name);
640
+ if (await fs$1.pathExists(targetFolder)) {
641
+ logger.info(`${icons.skip} Skipping ${template.name} (already exists)`);
642
+ continue;
643
+ }
644
+ logger.info(`${icons.download} Downloading ${template.name}...`);
645
+ const repoUrl = `https://github.com/${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}.git`;
646
+ await cloneSubdirectory(repoUrl, DEFAULT_TEMPLATE_REPO.branch, template.path, targetFolder);
647
+ logger.success(`${icons.check} Downloaded ${template.name}`);
648
+ }
649
+ logger.success(`\n${icons.check} All templates downloaded successfully!`);
650
+ } catch (error) {
651
+ throw new Error(`Failed to download templates: ${error.message}`);
652
+ }
653
+ }
534
654
  /**
535
655
  * Init command - initialize templates folder
536
656
  */
537
- const initCommand = new Command("init").description("Initialize templates folder structure at workspace root").action(async () => {
657
+ const initCommand = new Command("init").description("Initialize templates folder structure at workspace root").option("--no-download", "Skip downloading templates from repository").option("--path <path>", "Custom path for templates folder (relative to workspace root)").action(async (options) => {
538
658
  try {
539
659
  const workspaceRoot = await findWorkspaceRoot();
540
- const templatesPath = path.join(workspaceRoot, "templates");
660
+ const templatesPath = options.path ? path.join(workspaceRoot, options.path) : path.join(workspaceRoot, "templates");
541
661
  logger.info(`${icons.rocket} Initializing templates folder at: ${templatesPath}`);
542
662
  await fs$1.ensureDir(templatesPath);
543
- await fs$1.ensureDir(path.join(templatesPath, "boilerplates"));
544
- await fs$1.ensureDir(path.join(templatesPath, "scaffolds"));
545
663
  await fs$1.writeFile(path.join(templatesPath, "README.md"), `# Templates
546
664
 
547
665
  This folder contains boilerplate templates and scaffolding methods for your projects.
548
666
 
549
- ## Structure
667
+ ## Templates
550
668
 
551
- - \`boilerplates/\` - Full project boilerplate templates
552
- - \`scaffolds/\` - Feature scaffolding methods for existing projects
669
+ Templates are organized by framework/technology and include configuration files (\`scaffold.yaml\`) that define:
670
+ - Boilerplates: Full project starter templates
671
+ - Features: Code scaffolding methods for adding new features to existing projects
553
672
 
554
- ## Adding Templates
673
+ ## Adding More Templates
555
674
 
556
675
  Use the \`add\` command to add templates from remote repositories:
557
676
 
@@ -559,31 +678,38 @@ Use the \`add\` command to add templates from remote repositories:
559
678
  scaffold-mcp add --name my-template --url https://github.com/user/template
560
679
  \`\`\`
561
680
 
562
- ## Creating Custom Templates
681
+ Or add templates from subdirectories:
563
682
 
564
- ### Boilerplate Template Structure
683
+ \`\`\`bash
684
+ scaffold-mcp add --name nextjs-template --url https://github.com/user/repo/tree/main/templates/nextjs
685
+ \`\`\`
565
686
 
566
- Each boilerplate should have:
567
- - \`boilerplate.yaml\` - Configuration file
568
- - Template files with variable placeholders using Liquid syntax (\`{{ variableName }}\`)
687
+ ## Creating Custom Templates
569
688
 
570
- ### Scaffold Method Structure
689
+ Each template should have a \`scaffold.yaml\` configuration file defining:
690
+ - \`boilerplate\`: Array of boilerplate configurations
691
+ - \`features\`: Array of feature scaffold configurations
571
692
 
572
- Each scaffold method should have:
573
- - \`scaffold.yaml\` - Configuration file
574
- - Template files organized by project type
693
+ Template files use Liquid syntax for variable placeholders: \`{{ variableName }}\`
575
694
 
576
- See documentation for more details on template creation.
695
+ See existing templates for examples and documentation for more details.
577
696
  `);
578
- logger.success(`${icons.check} Templates folder initialized successfully!`);
579
- logger.header(`\n${icons.folder} Created structure:`);
580
- logger.indent(`${templatesPath}/`);
581
- logger.indent(`├── boilerplates/`);
582
- logger.indent(`├── scaffolds/`);
583
- logger.indent(`└── README.md`);
584
- sections.nextSteps([`Add templates using: scaffold-mcp add --name <name> --url <url>`, `Or manually create templates in ${templatesPath}/`]);
697
+ logger.success(`${icons.check} Templates folder created!`);
698
+ if (options.download !== false) await downloadTemplates(templatesPath);
699
+ else logger.info(`${icons.skip} Skipping template download (use --download to enable)`);
700
+ logger.header(`\n${icons.folder} Templates location:`);
701
+ logger.indent(templatesPath);
702
+ const nextSteps = [];
703
+ if (options.download === false) {
704
+ nextSteps.push(`Download templates: scaffold-mcp init --download`);
705
+ nextSteps.push(`Add templates manually: scaffold-mcp add --name <name> --url <url>`);
706
+ } else {
707
+ nextSteps.push(`List available boilerplates: scaffold-mcp boilerplate list`);
708
+ nextSteps.push(`Add more templates: scaffold-mcp add --name <name> --url <url>`);
709
+ }
710
+ sections.nextSteps(nextSteps);
585
711
  } catch (error) {
586
- logger.error(`${icons.cross} Error initializing templates folder:`, error);
712
+ messages.error(`Error initializing templates folder: ${error.message}`);
587
713
  process.exit(1);
588
714
  }
589
715
  });
@@ -804,6 +930,213 @@ Template File Content Guidelines:
804
930
  }
805
931
  };
806
932
 
933
+ //#endregion
934
+ //#region src/prompts/ScaffoldApplicationPrompt.ts
935
+ /**
936
+ * Prompt for scaffolding a new application using boilerplate templates
937
+ */
938
+ var ScaffoldApplicationPrompt = class ScaffoldApplicationPrompt {
939
+ static PROMPT_NAME = "scaffold-application";
940
+ /**
941
+ * Get the prompt definition for MCP
942
+ */
943
+ getDefinition() {
944
+ return {
945
+ name: ScaffoldApplicationPrompt.PROMPT_NAME,
946
+ description: "Scaffold a new application from a boilerplate template",
947
+ arguments: [{
948
+ name: "request",
949
+ description: "Describe the application you want to create (optional)",
950
+ required: false
951
+ }]
952
+ };
953
+ }
954
+ /**
955
+ * Get the prompt messages
956
+ */
957
+ getMessages(args) {
958
+ const userRequest = args?.request || "";
959
+ return [{
960
+ role: "user",
961
+ content: {
962
+ type: "text",
963
+ text: `You are helping create a new application using the scaffold-mcp MCP tools.
964
+
965
+ ${userRequest ? `User request: ${userRequest}\n` : ""}
966
+ Your task is to scaffold a new application by following this workflow:
967
+
968
+ ## Step 1: List Available Boilerplates
969
+ Use the \`list-boilerplates\` tool to see all available project templates.
970
+
971
+ **What to look for:**
972
+ - Boilerplate name (e.g., "scaffold-nextjs-app", "scaffold-vite-app")
973
+ - Description of what the boilerplate creates
974
+ - Target folder where projects will be created (e.g., "apps", "packages")
975
+ - Required and optional variables in the variables_schema
976
+
977
+ ## Step 2: Gather Required Information
978
+ Based on the selected boilerplate's variables_schema, collect:
979
+ - **Project name**: Must be kebab-case (e.g., "my-new-app", not "MyNewApp")
980
+ - **Required variables**: All variables marked as required: true
981
+ - **Optional variables**: Variables with required: false (ask user if needed)
982
+
983
+ Common variables:
984
+ - \`appName\` or \`packageName\`: The project name (kebab-case)
985
+ - \`description\`: Brief description of what the project does
986
+ - \`author\`: Author name
987
+
988
+ ## Step 3: Execute the Boilerplate
989
+ Use the \`use-boilerplate\` tool with:
990
+ - \`boilerplateName\`: Exact name from list-boilerplates response
991
+ - \`variables\`: Object matching the variables_schema exactly
992
+
993
+ **Example:**
994
+ \`\`\`json
995
+ {
996
+ "boilerplateName": "scaffold-nextjs-app",
997
+ "variables": {
998
+ "appName": "my-dashboard",
999
+ "description": "Admin dashboard for managing users",
1000
+ "author": "John Doe"
1001
+ }
1002
+ }
1003
+ \`\`\`
1004
+
1005
+ ## Important Guidelines:
1006
+ - **Always call \`list-boilerplates\` first** to see available options and their schemas
1007
+ - **Use exact variable names** from the schema (case-sensitive)
1008
+ - **Provide all required variables** - the tool will fail if any are missing
1009
+ - **Use kebab-case for project names** (e.g., "user-dashboard", not "UserDashboard")
1010
+ - The tool will create the project in the appropriate directory automatically
1011
+ - After creation, inform the user where the project was created
1012
+
1013
+ ## Example Workflow:
1014
+ 1. Call \`list-boilerplates\` → See available templates
1015
+ 2. Ask user which template to use (or infer from request)
1016
+ 3. Collect required variables based on schema
1017
+ 4. Call \`use-boilerplate\` with boilerplateName and variables
1018
+ 5. Report success and next steps to the user`
1019
+ }
1020
+ }];
1021
+ }
1022
+ };
1023
+
1024
+ //#endregion
1025
+ //#region src/prompts/ScaffoldFeaturePrompt.ts
1026
+ /**
1027
+ * Prompt for scaffolding a new feature in an existing project
1028
+ */
1029
+ var ScaffoldFeaturePrompt = class ScaffoldFeaturePrompt {
1030
+ static PROMPT_NAME = "scaffold-feature";
1031
+ /**
1032
+ * Get the prompt definition for MCP
1033
+ */
1034
+ getDefinition() {
1035
+ return {
1036
+ name: ScaffoldFeaturePrompt.PROMPT_NAME,
1037
+ description: "Scaffold a new feature (page, component, service, etc.) in an existing project",
1038
+ arguments: [{
1039
+ name: "request",
1040
+ description: "Describe the feature you want to add (optional)",
1041
+ required: false
1042
+ }, {
1043
+ name: "projectPath",
1044
+ description: "Path to the project (e.g., \"apps/my-app\") - optional if can be inferred",
1045
+ required: false
1046
+ }]
1047
+ };
1048
+ }
1049
+ /**
1050
+ * Get the prompt messages
1051
+ */
1052
+ getMessages(args) {
1053
+ const userRequest = args?.request || "";
1054
+ const projectPath = args?.projectPath || "";
1055
+ return [{
1056
+ role: "user",
1057
+ content: {
1058
+ type: "text",
1059
+ text: `You are helping add a new feature to an existing project using the scaffold-mcp MCP tools.
1060
+
1061
+ ${userRequest ? `User request: ${userRequest}\n` : ""}${projectPath ? `Project path: ${projectPath}\n` : ""}
1062
+ Your task is to scaffold a new feature by following this workflow:
1063
+
1064
+ ## Step 1: Identify the Project
1065
+ Determine the project path where the feature will be added:
1066
+ - If projectPath is provided, use it
1067
+ - Otherwise, ask the user or infer from context (e.g., "apps/my-app", "packages/my-lib")
1068
+ - The path should point to a directory containing a \`project.json\` file
1069
+
1070
+ ## Step 2: List Available Scaffolding Methods
1071
+ Use the \`list-scaffolding-methods\` tool with the projectPath.
1072
+
1073
+ **What to look for:**
1074
+ - Feature name (e.g., "scaffold-nextjs-page", "scaffold-react-component")
1075
+ - Description of what files/code it generates
1076
+ - Required and optional variables in the variables_schema
1077
+ - The template type (derived from project's sourceTemplate)
1078
+
1079
+ **Example:**
1080
+ \`\`\`json
1081
+ {
1082
+ "projectPath": "apps/my-dashboard"
1083
+ }
1084
+ \`\`\`
1085
+
1086
+ ## Step 3: Gather Required Information
1087
+ Based on the selected scaffolding method's variables_schema, collect:
1088
+ - **Feature-specific variables**: Name, path, type, etc.
1089
+ - **Required variables**: All variables marked as required: true
1090
+ - **Optional variables**: Variables with required: false (ask user if needed)
1091
+
1092
+ Common variables:
1093
+ - \`componentName\` / \`pageName\` / \`serviceName\`: Name in PascalCase
1094
+ - \`componentPath\` / \`pagePath\`: Where to place the file (may use kebab-case)
1095
+ - Boolean flags: \`withTests\`, \`withLayout\`, \`withStyles\`, etc.
1096
+
1097
+ ## Step 4: Execute the Scaffolding Method
1098
+ Use the \`use-scaffold-method\` tool with:
1099
+ - \`projectPath\`: Same path from step 1
1100
+ - \`scaffold_feature_name\`: Exact name from list-scaffolding-methods response
1101
+ - \`variables\`: Object matching the variables_schema exactly
1102
+
1103
+ **Example:**
1104
+ \`\`\`json
1105
+ {
1106
+ "projectPath": "apps/my-dashboard",
1107
+ "scaffold_feature_name": "scaffold-nextjs-page",
1108
+ "variables": {
1109
+ "pageName": "UserProfile",
1110
+ "pagePath": "user/profile",
1111
+ "withLayout": true,
1112
+ "withTests": false
1113
+ }
1114
+ }
1115
+ \`\`\`
1116
+
1117
+ ## Important Guidelines:
1118
+ - **Always call \`list-scaffolding-methods\` first** with the projectPath
1119
+ - **Use exact variable names** from the schema (case-sensitive)
1120
+ - **Provide all required variables** - the tool will fail if any are missing
1121
+ - **Follow naming conventions**:
1122
+ - Component/Page/Service names: PascalCase (e.g., "UserProfile")
1123
+ - File paths: kebab-case or as specified in schema (e.g., "user/profile")
1124
+ - **Conditional files**: Files with \`?condition=true\` are only included when the variable is true
1125
+ - The tool will create files in the appropriate locations automatically
1126
+ - After creation, inform the user what files were created
1127
+
1128
+ ## Example Workflow:
1129
+ 1. Identify project path (provided or ask user)
1130
+ 2. Call \`list-scaffolding-methods\` → See available features for this project
1131
+ 3. Ask user which feature to add (or infer from request)
1132
+ 4. Collect required variables based on schema
1133
+ 5. Call \`use-scaffold-method\` with projectPath, scaffold_feature_name, and variables
1134
+ 6. Report success and list created files`
1135
+ }
1136
+ }];
1137
+ }
1138
+ };
1139
+
807
1140
  //#endregion
808
1141
  //#region src/services/BoilerplateGeneratorService.ts
809
1142
  /**
@@ -1552,9 +1885,7 @@ Best practices:
1552
1885
  - Use conditional includes with ?variableName=value for optional files
1553
1886
  - Use path mapping with -> when source and target paths differ
1554
1887
  - Use {{ variableName }} in target paths for dynamic file placement
1555
- - Avoid wildcards unless you have a good reason
1556
-
1557
- See templates/nextjs-15/scaffold.yaml features section for examples.`,
1888
+ - Avoid wildcards unless you have a good reason`,
1558
1889
  items: { type: "string" }
1559
1890
  },
1560
1891
  patterns: {
@@ -2150,6 +2481,8 @@ function createServer(options = {}) {
2150
2481
  const generateFeatureScaffoldTool = adminEnabled ? new GenerateFeatureScaffoldTool(templatesPath) : null;
2151
2482
  const generateBoilerplatePrompt = adminEnabled ? new GenerateBoilerplatePrompt() : null;
2152
2483
  const generateFeatureScaffoldPrompt = adminEnabled ? new GenerateFeatureScaffoldPrompt() : null;
2484
+ const scaffoldApplicationPrompt = new ScaffoldApplicationPrompt();
2485
+ const scaffoldFeaturePrompt = new ScaffoldFeaturePrompt();
2153
2486
  const server = new Server({
2154
2487
  name: "scaffold-mcp",
2155
2488
  version: "1.0.0"
@@ -2255,26 +2588,30 @@ Example workflow for feature:
2255
2588
  }
2256
2589
  throw new Error(`Unknown tool: ${name}`);
2257
2590
  });
2258
- if (adminEnabled) {
2259
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
2260
- const prompts = [];
2591
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
2592
+ const prompts = [];
2593
+ prompts.push(scaffoldApplicationPrompt.getDefinition());
2594
+ prompts.push(scaffoldFeaturePrompt.getDefinition());
2595
+ if (adminEnabled) {
2261
2596
  if (generateBoilerplatePrompt) prompts.push(generateBoilerplatePrompt.getDefinition());
2262
2597
  if (generateFeatureScaffoldPrompt) prompts.push(generateFeatureScaffoldPrompt.getDefinition());
2263
- return { prompts };
2264
- });
2265
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
2266
- const { name, arguments: args } = request.params;
2267
- if (name === GenerateBoilerplatePrompt.PROMPT_NAME) {
2268
- if (!generateBoilerplatePrompt) throw new Error("Prompt not available");
2269
- return { messages: generateBoilerplatePrompt.getMessages(args) };
2270
- }
2271
- if (name === GenerateFeatureScaffoldPrompt.PROMPT_NAME) {
2272
- if (!generateFeatureScaffoldPrompt) throw new Error("Prompt not available");
2273
- return { messages: generateFeatureScaffoldPrompt.getMessages(args) };
2274
- }
2275
- throw new Error(`Unknown prompt: ${name}`);
2276
- });
2277
- }
2598
+ }
2599
+ return { prompts };
2600
+ });
2601
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
2602
+ const { name, arguments: args } = request.params;
2603
+ if (name === ScaffoldApplicationPrompt.PROMPT_NAME) return { messages: scaffoldApplicationPrompt.getMessages(args) };
2604
+ if (name === ScaffoldFeaturePrompt.PROMPT_NAME) return { messages: scaffoldFeaturePrompt.getMessages(args) };
2605
+ if (name === GenerateBoilerplatePrompt.PROMPT_NAME) {
2606
+ if (!generateBoilerplatePrompt) throw new Error("Prompt not available");
2607
+ return { messages: generateBoilerplatePrompt.getMessages(args) };
2608
+ }
2609
+ if (name === GenerateFeatureScaffoldPrompt.PROMPT_NAME) {
2610
+ if (!generateFeatureScaffoldPrompt) throw new Error("Prompt not available");
2611
+ return { messages: generateFeatureScaffoldPrompt.getMessages(args) };
2612
+ }
2613
+ throw new Error(`Unknown prompt: ${name}`);
2614
+ });
2278
2615
  return server;
2279
2616
  }
2280
2617
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agiflowai/scaffold-mcp",
3
3
  "description": "MCP server for scaffolding applications with boilerplate templates",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "license": "AGPL-3.0",
6
6
  "author": "AgiflowIO",
7
7
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "js-yaml": "4.1.0",
43
43
  "liquidjs": "10.21.1",
44
44
  "zod": "3.25.76",
45
- "@agiflowai/scaffold-generator": "0.1.0"
45
+ "@agiflowai/scaffold-generator": "0.3.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/express": "^5.0.0",