Skip to main content
Glama

create

Generate n8n workflows with real nodes using proper naming conventions and project organization for automation development.

Instructions

Create a new n8n workflow with REAL nodes only (no mock/placeholder nodes allowed). IMPORTANT: Use dashes in filenames, not underscores (e.g., "my-workflow" not "my_workflow")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesWorkflow name (use dashes, not underscores)
workflowYesThe workflow JSON object
projectNoOptional project name (only for multi-project repos)

Implementation Reference

  • Core implementation of the 'create' tool: handles file creation, validation, auto-fixing, documentation updates, and returns success message.
    async createWorkflow(name: string, workflow: any, project?: string): Promise<any> {
      try {
        // Enforce dash naming convention
        if (name.includes('_')) {
          name = name.replace(/_/g, '-');
          console.log(`πŸ“ Converting underscores to dashes in filename: ${name}`);
        }
        
        // Initialize workflows structure if needed (first time)
        const wasInitialized = await this.initializer.initialize();
        
        let targetPath: string;
        let relativePath: string;
    
        // Determine where to create the workflow based on structure
        if (this.structure.type === 'simple' || !project) {
          // Simple structure: use ./flows/ (workflowsPath already points to workflows dir)
          targetPath = path.join(this.workflowsPath, 'flows');
          relativePath = `flows/${name}.json`;
        } else if (this.structure.type === 'multi-project' && project) {
          // Multi-project structure with project specified
          targetPath = path.join(this.workflowsPath, project, 'workflows');
          relativePath = `${project}/workflows/${name}.json`;
        } else {
          // Unknown structure: default to simple with flows
          targetPath = path.join(this.workflowsPath, 'flows');
          relativePath = `flows/${name}.json`;
        }
    
        // Create directory if it doesn't exist
        await fs.mkdir(targetPath, { recursive: true });
        
        // Generate a succinct, unique name
        const finalName = await this.generateUniqueName(name, targetPath);
        
        // Update the workflow's internal name to match
        if (workflow.name) {
          workflow.name = finalName;
        }
        
        // Write temporary file for validation in /tmp
        const tempPath = `/tmp/mcflow_validate_${Date.now()}_${finalName}.json`;
        await fs.writeFile(tempPath, stringifyWorkflowFile(workflow));
    
        // Validate and auto-fix if needed
        const validationResult = await this.validator.validateWorkflow(tempPath);
        if (!validationResult.valid) {
          // Try to auto-fix
          const fixResult = await this.validator.autoFixWorkflow(tempPath);
          if (fixResult.fixed) {
            // Re-read the fixed workflow
            const fixedContent = await fs.readFile(tempPath, 'utf-8');
            workflow = JSON.parse(fixedContent);
          }
        }
    
        // Write the final workflow file with proper formatting
        const filePath = path.join(targetPath, `${finalName}.json`);
        await fs.writeFile(filePath, stringifyWorkflowFile(workflow));
        
        // Remove temp file
        try {
          await fs.unlink(tempPath);
        } catch {}
        
        // Update the relative path with the final name
        if (this.structure.type === 'simple' || !project) {
          relativePath = `workflows/flows/${finalName}.json`;
        } else if (project) {
          relativePath = `${project}/workflows/${finalName}.json`;
        }
        
        // Update documentation
        try {
          const customInstructions = await this.documenter.getCustomInstructions();
          await this.documenter.updateWorkflowDocumentation(finalName, workflow, 'create', customInstructions);
          
          // Extract and update credentials
          const credentials = this.initializer.extractCredentialsFromWorkflow(workflow);
          if (credentials.size > 0) {
            await this.initializer.updateEnvExample(credentials);
          }
          
          // Update README with workflow list
          const allWorkflows = await this.getWorkflowList();
          await this.initializer.updateReadmeWorkflowList(allWorkflows);
        } catch (docError) {
          console.error('Failed to update documentation:', docError);
          // Don't fail the workflow creation if documentation fails
        }
        
        return {
          content: [
            {
              type: 'text',
              text: `βœ… Workflow Created Successfully!\n\n` +
                    `πŸ“ File: ${relativePath}\n` +
                    `πŸ“ Name: ${finalName}\n` +
                    `${project ? `πŸ“‚ Project: ${project}\n` : ''}` +
                    `\n` +
                    `The workflow has been saved and documented.`,
            },
          ],
        };
      } catch (error) {
        throw new Error(`Failed to create workflow: ${error}`);
      }
    }
  • Input schema and description for the MCP 'create' tool.
    {
      name: 'create',
      description: 'Create a new n8n workflow with REAL nodes only (no mock/placeholder nodes allowed). IMPORTANT: Use dashes in filenames, not underscores (e.g., "my-workflow" not "my_workflow")',
      inputSchema: {
        type: 'object',
        properties: {
          name: {
            type: 'string',
            description: 'Workflow name (use dashes, not underscores)',
          },
          workflow: {
            type: 'object',
            description: 'The workflow JSON object',
          },
          project: {
            type: 'string',
            description: 'Optional project name (only for multi-project repos)',
          },
        },
        required: ['name', 'workflow'],
      },
    },
  • Registers the MCP tools (including 'create') by providing tool definitions and handling tool calls via ToolHandler.
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: getToolDefinitions(),
    }));
    
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      return await this.toolHandler.handleTool(
        request.params.name,
        request.params.arguments
      );
    });
  • ToolHandler switch case that routes 'create' tool calls to WorkflowManager.createWorkflow.
    case 'create':
      return await this.workflowManager.createWorkflow(
        args?.name as string,
        args?.workflow as any,
        args?.project as string
      );

Latest Blog Posts

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/mckinleymedia/mcflow-mcp'

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