Skip to main content
Glama

export

Export n8n workflows to JSON files for backup, sharing, or migration. Specify individual workflows or export all at once with customizable output formatting.

Instructions

Export workflows from n8n - replaces "n8n export:workflow" command

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idNoWorkflow ID to export
allNoExport all workflows
outputPathNoOutput directory path (defaults to workflows/flows)
prettyNoFormat JSON output prettily (default: true)

Implementation Reference

  • Core implementation of the export tool: executes n8n CLI export:workflow command, handles single workflow by ID or all workflows, saves them as separate JSON files in the specified output directory (defaults to workflows/flows), preserving workflow IDs.
    async exportWorkflow(options: {
      id?: string;
      all?: boolean;
      outputPath?: string;
      pretty?: boolean;
    } = {}): Promise<any> {
      try {
        const outputDir = options.outputPath || path.join(this.workflowsPath, 'flows');
        
        // Ensure output directory exists
        await fs.mkdir(outputDir, { recursive: true });
        
        // Build command - n8n requires a file path, not directory
        let command = 'n8n export:workflow';
        
        if (options.all) {
          // For all workflows, we need to export to a temp file and process
          const tempFile = path.join('/tmp', `n8n-export-${Date.now()}.json`);
          command += ` --all --output="${tempFile}"`;
          
          if (options.pretty !== false) {
            command += ' --pretty';
          }
          
          console.error(`Executing: ${command}`);
          const { stdout, stderr } = await execAsync(command);
          
          if (this.hasRealError(stderr, stdout)) {
            throw new Error(stderr);
          }
          
          // Read the exported data
          const exportedData = await fs.readFile(tempFile, 'utf-8');
          const workflows = JSON.parse(exportedData);
          
          // Save each workflow separately, preserving ID
          for (const workflow of workflows) {
            const fileName = `${workflow.name.toLowerCase().replace(/\s+/g, '-')}.json`;
            const filePath = path.join(outputDir, fileName);
            
            // Store the full workflow object with ID
            await fs.writeFile(filePath, JSON.stringify(workflow, null, 2));
          }
          
          // Clean up temp file
          await fs.unlink(tempFile).catch(() => {});
          
          return {
            content: [{
              type: 'text',
              text: `✅ Exported ${workflows.length} workflows to ${outputDir}`
            }]
          };
        } else if (options.id) {
          // For single workflow, export directly
          const tempFile = path.join('/tmp', `n8n-export-${Date.now()}.json`);
          command += ` --id=${options.id} --output="${tempFile}"`;
          
          if (options.pretty !== false) {
            command += ' --pretty';
          }
          
          console.error(`Executing: ${command}`);
          const { stdout, stderr } = await execAsync(command);
          
          if (this.hasRealError(stderr, stdout)) {
            throw new Error(stderr);
          }
          
          // Read the exported data
          const exportedData = await fs.readFile(tempFile, 'utf-8');
          const workflows = JSON.parse(exportedData);
          const workflow = Array.isArray(workflows) ? workflows[0] : workflows;
          
          // Save with the workflow's name, preserving ID
          const fileName = `${workflow.name.toLowerCase().replace(/\s+/g, '-')}.json`;
          const filePath = path.join(outputDir, fileName);
          
          // Store the full workflow object with ID
          await fs.writeFile(filePath, JSON.stringify(workflow, null, 2));
          
          // Clean up temp file
          await fs.unlink(tempFile).catch(() => {});
          
          return {
            content: [{
              type: 'text',
              text: `✅ Exported workflow: ${workflow.name}\n` +
                    `📁 File: ${fileName}\n` +
                    `🆔 ID: ${workflow.id}`
            }]
          };
        }
        
        // If no specific options, show error
        return {
          content: [{
            type: 'text',
            text: '❌ Please specify either --id or --all for export'
          }]
        };
      } catch (error: any) {
        throw new Error(`Failed to export workflow: ${error.message}`);
      }
    }
  • ToolHandler switch case that receives tool calls for 'export' and delegates to N8nManager.exportWorkflow with parsed arguments.
    case 'export':
      return await this.n8nManager.exportWorkflow({
        id: args?.id as string,
        all: args?.all as boolean,
        outputPath: args?.outputPath as string,
        pretty: args?.pretty as boolean,
      });
  • Tool schema definition including name, description, and input schema for the 'export' tool, returned by getToolDefinitions().
    {
      name: 'export',
      description: 'Export workflows from n8n - replaces "n8n export:workflow" command',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Workflow ID to export',
          },
          all: {
            type: 'boolean',
            description: 'Export all workflows',
          },
          outputPath: {
            type: 'string',
            description: 'Output directory path (defaults to workflows/flows)',
          },
          pretty: {
            type: 'boolean',
            description: 'Format JSON output prettily (default: true)',
          },
        },
      },
    },
  • Registers the tools (including 'export') with the MCP server by handling ListToolsRequest (via getToolDefinitions) and CallToolRequest (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
      );
    });
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states this 'replaces' a CLI command, implying it performs a similar function, but doesn't clarify if this is a read-only operation, what permissions are needed, whether it modifies data, or what the output entails (e.g., file creation, data format). For a tool with no annotations, this leaves significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's function. It avoids unnecessary words, though the reference to a CLI command might be slightly cryptic without context. It's appropriately sized for a tool with a clear purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and no output schema, the description is incomplete for a tool with 4 parameters. It doesn't explain what 'export' entails (e.g., file output, data format), behavioral traits like side effects, or how to interpret results. For a tool that likely generates outputs (implied by 'export'), this lack of context is a significant gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters (id, all, outputPath, pretty) with clear descriptions. The description adds no additional meaning about parameters beyond what's in the schema, such as explaining interactions (e.g., 'id' vs. 'all') or default behaviors. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Export workflows from n8n') and the resource ('workflows'), making the purpose understandable. However, it doesn't differentiate this tool from sibling tools like 'deploy' or 'execute' that might also handle workflows, nor does it explain what 'export' means in this context beyond referencing a CLI command replacement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It mentions it replaces a specific CLI command ('n8n export:workflow'), but this doesn't help an AI agent understand usage context relative to siblings like 'deploy' or 'execute'. There are no explicit when/when-not instructions or named alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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