Skip to main content
Glama

AI Code Toolkit

by AgiFlow
GenerateBoilerplateFileTool.ts8.29 kB
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; import { ProjectConfigResolver } from '@agiflowai/aicode-utils'; import { BoilerplateGeneratorService } from '../services/BoilerplateGeneratorService'; import type { ToolDefinition } from './types'; /** * Tool to generate template files for boilerplates and features */ export class GenerateBoilerplateFileTool { static readonly TOOL_NAME = 'generate-boilerplate-file'; private boilerplateGeneratorService: BoilerplateGeneratorService; private isMonolith: boolean; constructor(templatesPath: string, isMonolith: boolean = false) { this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath); this.isMonolith = isMonolith; } /** * Get the tool definition for MCP */ getDefinition(): ToolDefinition { // Build properties object const properties: Record<string, any> = {}; // In monolith mode, templateName is optional (read from toolkit.yaml) // In monorepo mode, templateName is required if (!this.isMonolith) { properties.templateName = { type: 'string', description: 'Name of the template folder (must already exist)', }; } // Add common properties Object.assign(properties, { filePath: { type: 'string', description: 'Path of the file to create within the template (e.g., "package.json", "src/app/page.tsx")', }, content: { type: 'string', description: `Content of the template file using Liquid template syntax. LIQUID SYNTAX: - Variables: {{ variableName }} - Replaced with actual values - Conditionals: {% if condition %}...{% endif %} - Conditional rendering - Else: {% if condition %}...{% else %}...{% endif %} - Elsif: {% if condition %}...{% elsif other %}...{% endif %} - Equality: {% if var == 'value' %}...{% endif %} AVAILABLE FILTERS: You can transform variables using these filters with the pipe (|) syntax: Case Conversion: - {{ name | camelCase }} - Convert to camelCase (myVariableName) - {{ name | pascalCase }} - Convert to PascalCase (MyVariableName) - {{ name | titleCase }} - Convert to TitleCase (alias for pascalCase) - {{ name | kebabCase }} - Convert to kebab-case (my-variable-name) - {{ name | snakeCase }} - Convert to snake_case (my_variable_name) - {{ name | upperCase }} - Convert to UPPER_CASE (MY_VARIABLE_NAME) - {{ name | lower }} or {{ name | downcase }} - Convert to lowercase - {{ name | upper }} or {{ name | upcase }} - Convert to UPPERCASE String Manipulation: - {{ name | strip }} - Remove leading/trailing whitespace - {{ name | replace: "old", "new" }} - Replace text (e.g., replace: "Tool", "") - {{ name | pluralize }} - Add plural suffix (simple: book → books, class → classes) - {{ name | singularize }} - Remove plural suffix (simple: books → book) Chaining Filters: - {{ toolName | downcase | replace: "tool", "" | strip }} - Combine multiple filters Example with variables and conditionals: { "name": "{{ packageName }}",{% if withFeature %} "feature": "enabled",{% endif %} "dependencies": { "core": "1.0.0"{% if withOptional %}, "optional": "2.0.0"{% endif %} } } Example with filters: export class {{ serviceName | pascalCase }} { private {{ serviceName | camelCase }}: string; constructor() { this.{{ serviceName | camelCase }} = "{{ serviceName | kebabCase }}"; } } IMPORTANT - Keep content minimal and business-agnostic: - Focus on structure and patterns, not specific business logic - Use placeholder data and generic examples - Include only essential boilerplate code - Demonstrate the pattern, not a complete implementation - Let AI fill in business-specific logic later Example (good - minimal): export function {{ functionName }}() { // TODO: Implement logic return null; } Example (bad - too specific): export function calculateTax(income: number) { const federalRate = 0.22; const stateRate = 0.05; return income * (federalRate + stateRate); }`, }, sourceFile: { type: 'string', description: 'Optional: Path to a source file to copy and convert to a template', }, header: { type: 'string', description: `Optional: Header comment to add at the top of the file to provide AI hints about design patterns, coding standards, and best practices. Example format for TypeScript/JavaScript files: /** * {{ componentName }} Component * * DESIGN PATTERNS: * - Component pattern description * - Architecture decisions * * CODING STANDARDS: * - Naming conventions * - Required elements * * AVOID: * - Common pitfalls * - Anti-patterns */ The header helps AI understand and follow established patterns when working with generated code.`, }, }); // Build required array based on mode const required = ['filePath']; if (!this.isMonolith) { required.unshift('templateName'); } return { name: GenerateBoilerplateFileTool.TOOL_NAME, description: `Create or update template files for boilerplates or features in the specified template directory. This tool: - Creates template files with .liquid extension for variable substitution - Supports creating nested directory structures - Can create files from source files (copying and converting to templates) - Validates that the template directory exists - Works for both boilerplate includes and feature scaffold includes IMPORTANT - Always add header comments: - For code files (*.ts, *.tsx, *.js, *.jsx), ALWAYS include a header parameter with design patterns, coding standards, and things to avoid - Headers help AI understand and follow established patterns when working with generated code - Use the header parameter to document the architectural decisions and best practices Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`, inputSchema: { type: 'object', properties, required, additionalProperties: false, }, }; } /** * Execute the tool */ async execute(args: { templateName?: string; filePath: string; content?: string; sourceFile?: string; header?: string; }): Promise<CallToolResult> { try { let { templateName } = args; // In monolith mode, read templateName from toolkit.yaml if not provided if (this.isMonolith && !templateName) { try { const config = await ProjectConfigResolver.resolveProjectConfig(process.cwd()); templateName = config.sourceTemplate; } catch (error) { return { content: [ { type: 'text', text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } // Validate required parameter if (!templateName) { return { content: [ { type: 'text', text: 'Missing required parameter: templateName', }, ], isError: true, }; } const result = await this.boilerplateGeneratorService.createTemplateFile({ ...args, templateName, }); if (!result.success) { return { content: [ { type: 'text', text: result.message, }, ], isError: true, }; } return { content: [ { type: 'text', text: JSON.stringify( { success: true, message: result.message, filePath: result.filePath, fullPath: result.fullPath, sourceFile: args.sourceFile || null, }, null, 2, ), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error creating template file: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgiFlow/aicode-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server