@agiflowai/scaffold-mcp 0.0.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 ADDED
@@ -0,0 +1,264 @@
1
+ # @agiflowai/scaffold-mcp
2
+
3
+ A Model Context Protocol (MCP) server for scaffolding applications with boilerplate templates and feature generators. Supports multiple transport modes: **stdio**, **HTTP**, **SSE**, and **CLI**.
4
+
5
+ ## Features
6
+
7
+ - **Boilerplate scaffolding**: Generate complete application structures from templates
8
+ - **Feature scaffolding**: Add features to existing projects with custom generators
9
+ - **Custom generators**: Template-specific TypeScript generators for advanced scaffolding logic
10
+ - **Liquid templating**: Use powerful templating engine for dynamic file generation
11
+ - **Variable replacement**: Customize generated code with context-aware variable substitution
12
+ - **Dynamic template discovery**: Automatically finds templates in your workspace
13
+ - **Template management**: Initialize templates folder and add templates from remote repositories
14
+ - **Multiple frameworks**: Support for Next.js, Vite React, and custom boilerplates
15
+ - **Multiple modes**: MCP server mode (stdio/HTTP/SSE) and standalone CLI mode
16
+ - **MCP integration**: Seamlessly works with Claude Desktop and other MCP-compatible clients
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm install @agiflowai/scaffold-mcp
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### 1. MCP Server
27
+
28
+ Run scaffold-mcp as an MCP server to integrate with Claude Desktop or other MCP clients.
29
+
30
+ #### Starting the Server
31
+
32
+ ```bash
33
+ # stdio transport (default) - for Claude Desktop
34
+ npx @agiflowai/scaffold-mcp mcp-serve
35
+
36
+ # HTTP transport - for web applications
37
+ npx @agiflowai/scaffold-mcp mcp-serve --type http --port 3000
38
+
39
+ # SSE transport - for legacy clients
40
+ npx @agiflowai/scaffold-mcp mcp-serve --type sse --port 3000
41
+
42
+ # Enable admin mode (template generation tools)
43
+ npx @agiflowai/scaffold-mcp mcp-serve --admin-enable
44
+ ```
45
+
46
+ **Server Options:**
47
+ - `-t, --type <type>`: Transport type: `stdio`, `http`, or `sse` (default: `stdio`)
48
+ - `-p, --port <port>`: Port for HTTP/SSE servers (default: `3000`)
49
+ - `--host <host>`: Host to bind to for HTTP/SSE (default: `localhost`)
50
+ - `--admin-enable`: Enable admin tools for template generation
51
+
52
+ #### Claude Desktop Configuration
53
+
54
+ Add to your Claude Desktop config:
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "scaffold-mcp": {
60
+ "command": "npx",
61
+ "args": ["-y", "@agiflowai/scaffold-mcp", "mcp-serve"]
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ Or if installed globally:
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "scaffold-mcp": {
73
+ "command": "scaffold-mcp",
74
+ "args": ["mcp-serve"]
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ **To enable admin tools** (for template creation), add the `--admin-enable` flag:
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "scaffold-mcp": {
86
+ "command": "npx",
87
+ "args": ["-y", "@agiflowai/scaffold-mcp", "mcp-serve", "--admin-enable"]
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ #### Available MCP Tools
94
+
95
+ **Standard Tools** (always available):
96
+
97
+ 1. **list-boilerplates**: List all available project boilerplates
98
+ - Returns: Array of boilerplate configurations with schemas
99
+
100
+ 2. **use-boilerplate**: Create a new project from a boilerplate template
101
+ - Arguments:
102
+ - `boilerplateName` (string): Name of the boilerplate
103
+ - `variables` (object): Variables matching the boilerplate's schema
104
+
105
+ 3. **list-scaffolding-methods**: List available features for a project
106
+ - Arguments:
107
+ - `projectPath` (string): Absolute path to project directory
108
+
109
+ 4. **use-scaffold-method**: Add a feature to an existing project
110
+ - Arguments:
111
+ - `projectPath` (string): Absolute path to project directory
112
+ - `scaffold_feature_name` (string): Name of the feature to add
113
+ - `variables` (object): Variables for the feature
114
+
115
+ 5. **write-to-file**: Write content to a file
116
+ - Arguments:
117
+ - `file_path` (string): Path to the file
118
+ - `content` (string): Content to write
119
+
120
+ **Admin Tools** (enabled with `--admin-enable` flag):
121
+
122
+ 6. **generate-boilerplate**: Create a new boilerplate configuration in a template's scaffold.yaml
123
+ - Arguments:
124
+ - `templateName` (string): Name of the template folder
125
+ - `boilerplateName` (string): Name of the boilerplate (kebab-case)
126
+ - `description` (string): Detailed description
127
+ - `targetFolder` (string): Target folder for projects
128
+ - `variables` (array): Variable definitions with schema
129
+ - `includes` (array): Template files to include
130
+ - `instruction` (string, optional): Usage instructions
131
+
132
+ 7. **generate-feature-scaffold**: Create a new feature configuration in a template's scaffold.yaml
133
+ - Arguments:
134
+ - `templateName` (string): Name of the template folder
135
+ - `featureName` (string): Name of the feature (kebab-case)
136
+ - `description` (string): Feature description
137
+ - `variables` (array): Variable definitions with schema
138
+ - `includes` (array, optional): Template files to include
139
+ - `patterns` (array, optional): File patterns this feature works with
140
+ - `instruction` (string, optional): Usage instructions
141
+
142
+ 8. **generate-boilerplate-file**: Create template files for boilerplates or features
143
+ - Arguments:
144
+ - `templateName` (string): Name of the template folder
145
+ - `filePath` (string): Path of the file within the template
146
+ - `content` (string): File content with Liquid variables
147
+ - `header` (string, optional): Header comment for AI hints
148
+ - `sourceFile` (string, optional): Copy from existing source file
149
+
150
+ ### 2. CLI Commands
151
+
152
+ Use scaffold-mcp as a standalone CLI tool for template management and scaffolding.
153
+
154
+ #### Template Management
155
+
156
+ ```bash
157
+ # Initialize templates folder
158
+ scaffold-mcp init
159
+ scaffold-mcp init --path /path/to/templates
160
+
161
+ # Add templates from repositories
162
+ 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
164
+ ```
165
+
166
+ #### Boilerplate Commands
167
+
168
+ ```bash
169
+ # List available boilerplates
170
+ scaffold-mcp boilerplate list
171
+
172
+ # Show boilerplate details
173
+ scaffold-mcp boilerplate info <boilerplate-name>
174
+
175
+ # Create project from boilerplate
176
+ scaffold-mcp boilerplate create <name> --vars '{"appName":"my-app"}'
177
+ scaffold-mcp boilerplate create nextjs-15-boilerplate \
178
+ --vars '{"projectName":"my-app","packageName":"@myorg/my-app"}' \
179
+ --verbose
180
+ ```
181
+
182
+ #### Scaffold Commands
183
+
184
+ ```bash
185
+ # List scaffolding methods for a project
186
+ scaffold-mcp scaffold list ./apps/my-app
187
+
188
+ # Show scaffold method details
189
+ scaffold-mcp scaffold info <feature-name> --project ./apps/my-app
190
+
191
+ # Add feature to project
192
+ scaffold-mcp scaffold add <feature> --project ./apps/my-app --vars '{"name":"MyFeature"}'
193
+ scaffold-mcp scaffold add scaffold-nextjs-page \
194
+ --project ./apps/my-app \
195
+ --vars '{"pageTitle":"About Us","nextjsPagePath":"/about"}' \
196
+ --verbose
197
+ ```
198
+
199
+ #### Environment Variables
200
+
201
+ - `MCP_PORT`: Port number for HTTP/SSE servers (default: 3000)
202
+ - `MCP_HOST`: Host for HTTP/SSE servers (default: localhost)
203
+
204
+ ## Quick Start
205
+
206
+ ### 1. Initialize Templates
207
+
208
+ ```bash
209
+ # Initialize templates folder in your project
210
+ scaffold-mcp init
211
+
212
+ # Or specify a custom path
213
+ scaffold-mcp init --path ./my-templates
214
+ ```
215
+
216
+ ### 2. Add Templates
217
+
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
221
+
222
+ # Add a scaffold template
223
+ scaffold-mcp add --name react-component --url https://github.com/yourorg/react-component-scaffold --type scaffold
224
+ ```
225
+
226
+ ### 3. Create a New Project
227
+
228
+ ```bash
229
+ # List available boilerplates
230
+ scaffold-mcp boilerplate list
231
+
232
+ # Get info about a specific boilerplate
233
+ scaffold-mcp boilerplate info nextjs-15-boilerplate
234
+
235
+ # Create a new Next.js 15 project
236
+ scaffold-mcp boilerplate create nextjs-15-boilerplate \
237
+ --vars '{"projectName":"my-app","packageName":"@myorg/my-app","appName":"My App"}'
238
+ ```
239
+
240
+ ### 4. Add Features to Existing Projects
241
+
242
+ ```bash
243
+ # List available features for your project
244
+ scaffold-mcp scaffold list /path/to/your/project
245
+
246
+ # Get info about a specific scaffold method
247
+ scaffold-mcp scaffold info scaffold-nextjs-page --project /path/to/your/project
248
+
249
+ # Add a new Next.js page
250
+ scaffold-mcp scaffold add scaffold-nextjs-page \
251
+ --project /path/to/your/project \
252
+ --vars '{"pageTitle":"About Us","pageDescription":"Learn more","nextjsPagePath":"/about"}'
253
+ ```
254
+
255
+ ## Documentation
256
+
257
+ - [CLI Commands](./docs/cli-commands.md) - Complete CLI reference
258
+ - [MCP Tools](./docs/mcp-tools.md) - MCP server tools reference
259
+ - [Template Conventions](./docs/template-conventions.md) - Guide for creating templates with Liquid syntax
260
+ - [Advanced Generators](./docs/advanced-generators.md) - Guide for creating custom TypeScript generators
261
+
262
+ ## License
263
+
264
+ AGPL-3.0
@@ -0,0 +1,142 @@
1
+ import path from "node:path";
2
+ import yaml from "js-yaml";
3
+ import { z } from "zod";
4
+
5
+ //#region src/services/ScaffoldConfigLoader.ts
6
+ const VariablesSchemaSchema = z.object({
7
+ type: z.literal("object"),
8
+ properties: z.record(z.any()),
9
+ required: z.array(z.string()),
10
+ additionalProperties: z.boolean()
11
+ });
12
+ const ScaffoldConfigEntrySchema = z.object({
13
+ name: z.string(),
14
+ description: z.string().optional(),
15
+ instruction: z.string().optional(),
16
+ targetFolder: z.string().optional(),
17
+ variables_schema: VariablesSchemaSchema,
18
+ includes: z.array(z.string()),
19
+ generator: z.string().optional(),
20
+ patterns: z.array(z.string()).optional()
21
+ });
22
+ const ScaffoldYamlSchema = z.object({
23
+ boilerplate: z.union([ScaffoldConfigEntrySchema, z.array(ScaffoldConfigEntrySchema)]).optional(),
24
+ features: z.union([ScaffoldConfigEntrySchema, z.array(ScaffoldConfigEntrySchema)]).optional()
25
+ }).catchall(z.union([ScaffoldConfigEntrySchema, z.array(ScaffoldConfigEntrySchema)]));
26
+ var ScaffoldConfigLoader = class {
27
+ constructor(fileSystem, templateService) {
28
+ this.fileSystem = fileSystem;
29
+ this.templateService = templateService;
30
+ }
31
+ async parseArchitectConfig(templatePath) {
32
+ const architectPath = path.join(templatePath, "scaffold.yaml");
33
+ if (!await this.fileSystem.pathExists(architectPath)) return null;
34
+ try {
35
+ const content = await this.fileSystem.readFile(architectPath, "utf8");
36
+ const rawConfig = yaml.load(content);
37
+ return ScaffoldYamlSchema.parse(rawConfig);
38
+ } catch (error) {
39
+ if (error instanceof z.ZodError) {
40
+ const errorMessages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
41
+ throw new Error(`scaffold.yaml validation failed: ${errorMessages}`);
42
+ }
43
+ throw new Error(`Failed to parse scaffold.yaml: ${error instanceof Error ? error.message : String(error)}`);
44
+ }
45
+ }
46
+ parseIncludeEntry(includeEntry, variables) {
47
+ const [pathPart, conditionsPart] = includeEntry.split("?");
48
+ const conditions = {};
49
+ if (conditionsPart) {
50
+ const conditionPairs = conditionsPart.split("&");
51
+ for (const pair of conditionPairs) {
52
+ const [key, value] = pair.split("=");
53
+ if (key && value) conditions[key.trim()] = value.trim();
54
+ }
55
+ }
56
+ if (pathPart.includes("->")) {
57
+ const [sourcePath, targetPath] = pathPart.split("->").map((p) => p.trim());
58
+ return {
59
+ sourcePath,
60
+ targetPath: this.replaceVariablesInPath(targetPath, variables),
61
+ conditions
62
+ };
63
+ }
64
+ const processedPath = this.replaceVariablesInPath(pathPart.trim(), variables);
65
+ return {
66
+ sourcePath: pathPart.trim(),
67
+ targetPath: processedPath,
68
+ conditions
69
+ };
70
+ }
71
+ replaceVariablesInPath(pathStr, variables) {
72
+ return this.templateService.renderString(pathStr, variables);
73
+ }
74
+ shouldIncludeFile(conditions, variables) {
75
+ if (!conditions || Object.keys(conditions).length === 0) return true;
76
+ for (const [conditionKey, conditionValue] of Object.entries(conditions)) {
77
+ const variableValue = variables[conditionKey];
78
+ if (conditionValue === "true" || conditionValue === "false") {
79
+ const expectedBoolean = conditionValue === "true";
80
+ if (Boolean(variableValue) !== expectedBoolean) return false;
81
+ } else if (String(variableValue) !== conditionValue) return false;
82
+ }
83
+ return true;
84
+ }
85
+ async validateTemplate(templatePath, scaffoldType) {
86
+ const errors = [];
87
+ const missingFiles = [];
88
+ if (!await this.fileSystem.pathExists(templatePath)) {
89
+ errors.push(`Template directory ${templatePath} does not exist`);
90
+ return {
91
+ isValid: false,
92
+ errors,
93
+ missingFiles
94
+ };
95
+ }
96
+ let architectConfig;
97
+ try {
98
+ architectConfig = await this.parseArchitectConfig(templatePath);
99
+ } catch (error) {
100
+ errors.push(`Failed to parse scaffold.yaml: ${error instanceof Error ? error.message : String(error)}`);
101
+ return {
102
+ isValid: false,
103
+ errors,
104
+ missingFiles
105
+ };
106
+ }
107
+ if (!architectConfig) {
108
+ errors.push("scaffold.yaml not found in template directory");
109
+ return {
110
+ isValid: false,
111
+ errors,
112
+ missingFiles
113
+ };
114
+ }
115
+ if (!architectConfig[scaffoldType]) {
116
+ const availableTypes = Object.keys(architectConfig).join(", ");
117
+ errors.push(`Scaffold type '${scaffoldType}' not found in scaffold.yaml. Available types: ${availableTypes}`);
118
+ return {
119
+ isValid: false,
120
+ errors,
121
+ missingFiles
122
+ };
123
+ }
124
+ const config = architectConfig[scaffoldType];
125
+ if (config.includes && Array.isArray(config.includes)) for (const includeFile of config.includes) {
126
+ const parsed = this.parseIncludeEntry(includeFile, {});
127
+ const sourcePath = path.join(templatePath, parsed.sourcePath);
128
+ const liquidSourcePath = `${sourcePath}.liquid`;
129
+ const sourceExists = await this.fileSystem.pathExists(sourcePath);
130
+ const liquidExists = await this.fileSystem.pathExists(liquidSourcePath);
131
+ if (!sourceExists && !liquidExists) missingFiles.push(includeFile);
132
+ }
133
+ return {
134
+ isValid: errors.length === 0 && missingFiles.length === 0,
135
+ errors,
136
+ missingFiles
137
+ };
138
+ }
139
+ };
140
+
141
+ //#endregion
142
+ export { ScaffoldConfigLoader };
@@ -0,0 +1,3 @@
1
+ import { ScaffoldConfigLoader } from "./ScaffoldConfigLoader-CI0T6zdG.js";
2
+
3
+ export { ScaffoldConfigLoader };
@@ -0,0 +1,3 @@
1
+ import { ScaffoldService } from "./ScaffoldService-CnJ1nj1v.js";
2
+
3
+ export { ScaffoldService };