Back to N8n Mcp

Workflow Management Tools Guide

data/skills/n8n-mcp-tools-expert/WORKFLOW_GUIDE.md

2.66.331.2 KB
Original Source

Workflow Management Tools Guide

Complete guide for creating, updating, and managing n8n workflows.


Tool Availability

Requires n8n API: All tools in this guide need N8N_API_URL and N8N_API_KEY configured.

If unavailable, use template examples and validation-only workflows.


n8n_create_workflow

Speed: 100-500ms

Use when: Creating new workflows from scratch

Syntax:

javascript
n8n_create_workflow({
  name: "Webhook to Slack",  // Required
  nodes: [...],              // Required: array of nodes
  connections: {...},        // Required: connections object
  settings: {...}            // Optional: workflow settings
})

Returns: Created workflow with ID

Example:

javascript
n8n_create_workflow({
  name: "Webhook to Slack",
  nodes: [
    {
      id: "webhook-1",
      name: "Webhook",
      type: "n8n-nodes-base.webhook",  // Full prefix!
      typeVersion: 2,
      position: [250, 300],
      parameters: {
        path: "slack-notify",
        httpMethod: "POST"
      }
    },
    {
      id: "slack-1",
      name: "Slack",
      type: "n8n-nodes-base.slack",
      typeVersion: 2,
      position: [450, 300],
      parameters: {
        resource: "message",
        operation: "post",
        channel: "#general",
        text: "={{$json.body.message}}"
      }
    }
  ],
  connections: {
    "Webhook": {
      "main": [[{node: "Slack", type: "main", index: 0}]]
    }
  }
})

Notes:

  • Workflows created inactive (activate with activateWorkflow operation)
  • Auto-sanitization runs on creation
  • Validate before creating for best results

n8n_update_partial_workflow (MOST USED!)

Speed: 50-200ms | Uses: 38,287 (most used tool!)

Use when: Making incremental changes to workflows

Common pattern: 56s average between edits (iterative building!)

20 Operation Types

Node Operations (7 types):

  1. addNode - Add new node
  2. removeNode - Remove node by ID or name
  3. updateNode - Update node properties (use dot notation)
  4. patchNodeField - Surgical string edits via strict find/replace (see below)
  5. moveNode - Change position
  6. enableNode - Enable disabled node
  7. disableNode - Disable active node

Connection Operations (5 types): 8. addConnection - Connect nodes (supports smart params) 9. removeConnection - Remove connection (supports ignoreErrors) 10. rewireConnection - Change connection target 11. cleanStaleConnections - Auto-remove broken connections 12. replaceConnections - Replace entire connections object

Metadata Operations (5 types): 13. updateSettings - Workflow settings 14. updateName - Rename workflow 15. setNodeGroups - Replace the canvas groups (n8n 2.28+; see below) 16. addTag - Add tag 17. removeTag - Remove tag

Activation Operations (2 types): 18. activateWorkflow - Activate workflow for automatic execution 19. deactivateWorkflow - Deactivate workflow

Project Management Operations (1 type): 20. transferWorkflow - Transfer workflow to a different project (enterprise/cloud)

Intent Parameter (IMPORTANT!)

Always include intent for better responses:

javascript
n8n_update_partial_workflow({
  id: "workflow-id",
  intent: "Add error handling for API failures",  // Describe what you're doing
  operations: [...]
})

Smart Parameters

IF nodes - Use semantic branch names:

javascript
{
  type: "addConnection",
  source: "IF",
  target: "True Handler",
  branch: "true"  // Instead of sourceIndex: 0
}

{
  type: "addConnection",
  source: "IF",
  target: "False Handler",
  branch: "false"  // Instead of sourceIndex: 1
}

Switch nodes - Use semantic case numbers:

javascript
{
  type: "addConnection",
  source: "Switch",
  target: "Handler A",
  case: 0
}

{
  type: "addConnection",
  source: "Switch",
  target: "Handler B",
  case: 1
}

AI Connection Types (8 types)

Full support for AI workflows:

javascript
// Language Model
{
  type: "addConnection",
  source: "OpenAI Chat Model",
  target: "AI Agent",
  sourceOutput: "ai_languageModel"
}

// Tool
{
  type: "addConnection",
  source: "HTTP Request Tool",
  target: "AI Agent",
  sourceOutput: "ai_tool"
}

// Memory
{
  type: "addConnection",
  source: "Window Buffer Memory",
  target: "AI Agent",
  sourceOutput: "ai_memory"
}

// All 8 types:
// - ai_languageModel
// - ai_tool
// - ai_memory
// - ai_outputParser
// - ai_embedding
// - ai_vectorStore
// - ai_document
// - ai_textSplitter

Property Removal with null

Remove properties by setting them to null:

javascript
// Remove a property
{
  type: "updateNode",
  nodeName: "HTTP Request",
  updates: { onError: null }
}

// Migrate from deprecated property
{
  type: "updateNode",
  nodeName: "HTTP Request",
  updates: {
    continueOnFail: null,  // Remove old
    onError: "continueErrorOutput"  // Add new
  }
}

patchNodeField (Surgical String Edits)

Use patchNodeField for strict find/replace edits on string fields — code, HTML, email templates, JSON bodies. Unlike updateNode with __patch_find_replace (which silently warns on misses), patchNodeField is strict: it errors if the find string is not found, and errors if multiple matches are found (preventing ambiguous replacements).

When to use which:

  • patchNodeField — preferred for most string edits. Strict error handling catches mistakes early.
  • updateNode with __patch_find_replace — legacy approach. Tolerant (warns but continues on miss). Use only when you want lenient behavior.

Syntax:

javascript
{
  type: "patchNodeField",
  nodeName: "Code",           // or nodeId
  fieldPath: "parameters.jsCode",  // Dot-notation path to the string field
  patches: [
    {
      find: "const limit = 10;",
      replace: "const limit = 50;",
      replaceAll: false,       // Default: false. Set true to replace all occurrences
      regex: false             // Default: false. Set true to treat find as regex
    }
  ]
}

Examples:

javascript
// Basic strict find/replace in code
n8n_update_partial_workflow({
  id: "wf-123",
  intent: "Update API limit",
  operations: [{
    type: "patchNodeField",
    nodeName: "Code",
    fieldPath: "parameters.jsCode",
    patches: [{find: "const limit = 10;", replace: "const limit = 50;"}]
  }]
})

// Replace all occurrences of a URL
n8n_update_partial_workflow({
  id: "wf-123",
  intent: "Migrate API domain",
  operations: [{
    type: "patchNodeField",
    nodeName: "Code",
    fieldPath: "parameters.jsCode",
    patches: [{find: "api.old.com", replace: "api.new.com", replaceAll: true}]
  }]
})

// Regex-based replacement (whitespace-insensitive)
n8n_update_partial_workflow({
  id: "wf-123",
  intent: "Update limit with regex",
  operations: [{
    type: "patchNodeField",
    nodeName: "Code",
    fieldPath: "parameters.jsCode",
    patches: [{find: "const\\s+limit\\s*=\\s*\\d+", replace: "const limit = 100", regex: true}]
  }]
})

// Multiple sequential patches on an email template
n8n_update_partial_workflow({
  id: "wf-123",
  intent: "Update email footer",
  operations: [{
    type: "patchNodeField",
    nodeName: "Set Email",
    fieldPath: "parameters.assignments.assignments.6.value",
    patches: [
      {find: "© 2025", replace: "© 2026"},
      {find: "<p>Unsubscribe</p>", replace: ""}
    ]
  }]
})

Error behavior (this is what makes it strict):

  • Find string not found → operation fails with error (not a silent warning)
  • Multiple matches without replaceAll → operation fails (ambiguity detected)
  • Patches are applied sequentially — order matters

Security limits:

  • Max 50 patches per operation
  • Regex patterns capped at 500 characters
  • Regex only on fields under 512KB
  • ReDoS-safe: rejects nested quantifiers like (a+)+ and overlapping alternations like (\w|\d)+
  • Prototype pollution protection on field paths

Activation Operations

javascript
// Activate workflow
n8n_update_partial_workflow({
  id: "workflow-id",
  intent: "Activate workflow for production",
  operations: [{type: "activateWorkflow"}]
})

// Deactivate workflow
n8n_update_partial_workflow({
  id: "workflow-id",
  intent: "Deactivate workflow for maintenance",
  operations: [{type: "deactivateWorkflow"}]
})

Example Usage

javascript
n8n_update_partial_workflow({
  id: "workflow-id",
  intent: "Add transform node after IF condition",
  operations: [
    // Add node
    {
      type: "addNode",
      node: {
        name: "Transform",
        type: "n8n-nodes-base.set",
        position: [400, 300],
        parameters: {}
      }
    },
    // Connect it (smart parameter)
    {
      type: "addConnection",
      source: "IF",
      target: "Transform",
      branch: "true"  // Clear and semantic!
    }
  ]
})

Canvas Groups (n8n 2.28+)

A canvas group is a named frame drawn around a connected run of non-trigger nodes. Purely presentational — it changes nothing about execution — but n8n validates groups on every write, including writes that have nothing to do with grouping. That is the part worth understanding, because it used to make unrelated edits fail.

You do not have to manage groups to edit a grouped workflow. n8n-mcp reconciles them with the graph you produce, once, at the end of a diff:

  • A grouped node you remove is pruned from its group; the group survives on its remaining members.
  • A group left with no members is dropped.
  • A group n8n refuses (its members are no longer a single connected run) is ungrouped so your edit still lands. Nodes and connections are never altered to save a group.

Every adjustment comes back in details.warnings. Read them — they are the only signal that a user's grouping changed as a side effect of your edit.

Authoring groups with setNodeGroups. It replaces the whole list, like replaceConnections:

javascript
n8n_update_partial_workflow({
  id: "workflow-id",
  intent: "Group the enrichment steps",
  operations: [{
    type: "setNodeGroups",
    nodeGroups: [
      { name: "Enrich lead", nodeNames: ["Fetch company", "Score lead"] },
      { name: "Notify", nodeIds: ["a1b2c3d4"] }          // ids work too
    ]
  }]
})
  • Pass every group you want to keep — anything you omit is gone.
  • nodeGroups: [] ungroups everything.
  • Give each group nodeNames or nodeIds, not both populated. The group id is generated unless you supply one.
  • description is optional, max 155 characters, and only exists on n8n 2.32+. On older instances it is dropped with a warning rather than failing the write.

Creating a workflow with groups. n8n_create_workflow and n8n_update_full_workflow take the same field, in n8n's own shape — members are node IDs, because you are sending those nodes in the same payload:

javascript
n8n_create_workflow({
  name: "Lead pipeline",
  nodes: [...],
  connections: {...},
  nodeGroups: [{ name: "Enrich lead", nodeIds: ["fetch-company", "score-lead"] }]
})

On a full update the field follows the same rule as settings: omit it to keep the stored groups, pass [] to ungroup everything. An id that is not in nodes[] is an error, not something to repair quietly — you supplied both halves, so a mismatch is a bug in the request.

What n8n will reject. Members must form a single connected run with one way in and one way out, and a trigger can never be inside a group. n8n decides this, not n8n-mcp — so its message is returned to you verbatim. A group you asked for in this request is never silently discarded: if n8n refuses it you get an error, not a quiet success.

Node group "Enrich lead" (…) must form a single connected subgraph with a single entry and exit.
Node group "Enrich lead" (…) cannot contain trigger nodes: Manual Trigger.

When that happens, fix the selection — usually by including the node that sits between two members, or excluding the trigger — rather than retrying the same shape.

Older instances. Canvas groups do not exist before n8n 2.28. Authoring them there saves the workflow without groups and warns; it does not fail.

Reading groups. n8n_get_workflow returns nodeGroups in full, details and structure modes when the workflow has any. mode: "active" returns the published version's groups, which can differ from the draft's.

Cleanup & Recovery

cleanStaleConnections - Remove broken connections:

javascript
{type: "cleanStaleConnections"}

rewireConnection - Change target atomically:

javascript
{
  type: "rewireConnection",
  source: "Webhook",
  from: "Old Handler",
  to: "New Handler"
}

Best-effort mode - Apply what works:

javascript
n8n_update_partial_workflow({
  id: "workflow-id",
  operations: [...],
  continueOnError: true  // Don't fail if some operations fail
})

Validate before applying:

javascript
n8n_update_partial_workflow({
  id: "workflow-id",
  operations: [...],
  validateOnly: true  // Preview without applying
})

n8n_deploy_template (QUICK START!)

Speed: 200-500ms

Use when: Deploying a template directly to n8n instance

javascript
n8n_deploy_template({
  templateId: 2947,  // Required: from n8n.io
  name: "My Weather to Slack",  // Optional: custom name
  autoFix: true,  // Default: auto-fix common issues
  autoUpgradeVersions: true,  // Default: upgrade node versions
  stripCredentials: true  // Default: remove credential refs
})

Returns:

  • Workflow ID
  • Required credentials
  • Fixes applied

Example:

javascript
// Deploy a webhook to Slack template
const result = n8n_deploy_template({
  templateId: 2947,
  name: "Production Slack Notifier"
});

// Result includes:
// - id: "new-workflow-id"
// - requiredCredentials: ["slack"]
// - fixesApplied: ["typeVersion upgraded", "expression format fixed"]

n8n_workflow_versions (VERSION CONTROL)

Use when: Managing workflow history, rollback, cleanup

List Versions

javascript
n8n_workflow_versions({
  mode: "list",
  workflowId: "workflow-id",
  limit: 10
})

Get Specific Version

javascript
n8n_workflow_versions({
  mode: "get",
  versionId: 123
})

Rollback to Previous Version

javascript
n8n_workflow_versions({
  mode: "rollback",
  workflowId: "workflow-id",
  versionId: 123,  // Optional: specific version
  validateBefore: true  // Default: validate before rollback
})

Delete Versions

javascript
// Delete specific version
n8n_workflow_versions({
  mode: "delete",
  workflowId: "workflow-id",
  versionId: 123
})

// Delete all versions for workflow
n8n_workflow_versions({
  mode: "delete",
  workflowId: "workflow-id",
  deleteAll: true
})

Prune Old Versions

javascript
n8n_workflow_versions({
  mode: "prune",
  workflowId: "workflow-id",
  maxVersions: 10  // Keep 10 most recent
})

n8n_test_workflow (TRIGGER EXECUTION)

Use when: Testing workflow execution

Auto-detects trigger type (webhook, form, chat)

javascript
// Test webhook workflow
n8n_test_workflow({
  workflowId: "workflow-id",
  triggerType: "webhook",  // Optional: auto-detected
  httpMethod: "POST",
  data: {message: "Hello!"},
  waitForResponse: true,
  timeout: 120000
})

// Test chat workflow
n8n_test_workflow({
  workflowId: "workflow-id",
  triggerType: "chat",
  message: "Hello, AI agent!",
  sessionId: "session-123"  // For conversation continuity
})

n8n_manage_credentials (CREDENTIAL MANAGEMENT)

Speed: 50-500ms

Use when: Creating, updating, listing, or deleting credentials; discovering credential schemas

6 Actions

  1. list - List all credentials (id, name, type, timestamps)
  2. get - Get credential by ID (data field stripped)
  3. create - Create credential (requires name, type, data)
  4. update - Update credential by ID (name, data, and/or type)
  5. delete - Permanently delete credential by ID
  6. getSchema - Discover required fields for a credential type

list and get also accept an optional includeUsage: true flag that attaches workflow-usage info to each credential (see "Find Which Workflows Use a Credential" below).

List Credentials

javascript
n8n_manage_credentials({action: "list"})
// → [{id, name, type, createdAt, updatedAt}, ...]

Get Credential

javascript
n8n_manage_credentials({action: "get", id: "123"})
// → {id, name, type, ...} (data field stripped for security)
// Falls back to list+filter if GET returns 403/405

Find Which Workflows Use a Credential

n8n's public API has no native "which workflows use credential X" endpoint, so n8n-mcp builds the reverse index for you by scanning workflows client-side. Pass includeUsage: true to either list or get.

javascript
// Every credential, with the workflows that reference it
n8n_manage_credentials({action: "list", includeUsage: true})
// → {
//     credentials: [
//       {
//         id: "123",
//         name: "Production Slack",
//         type: "slackApi",
//         createdAt: "...", updatedAt: "...",
//         usedIn: [
//           {id: "wf_abc", name: "Daily digest",  active: true},
//           {id: "wf_xyz", name: "Alert fan-out", active: false}
//         ],
//         usageCount: 2
//       },
//       ...
//     ],
//     count: N,
//     // usageScanError: "..."  // present only if the workflow scan failed
//   }

// One credential, with its workflow references
n8n_manage_credentials({action: "get", id: "123", includeUsage: true})
// → Same shape as `get` plus usedIn and usageCount.
//   On scan failure: response sets usageScanError and omits usedIn/usageCount.

When to use it:

  • Before delete: confirm nothing references the credential
  • Before rotating a secret with update: see exactly which workflows you'll affect
  • After n8n_audit_instance flags a credential: locate the workflows that need remediation

Behavior and limits:

  • The reverse index is built client-side, deduplicated per workflow, and capped at 5000 workflows (same ceiling as n8n_audit_instance)
  • Archived workflows are excluded by n8n's API — a "no usages" result does not prove a credential is unused; verify before destructive actions
  • Triggers one full workflow scan per call. On large instances expect slower responses than the base ~50–500ms — budget accordingly when calling repeatedly
  • If the scan fails, the response degrades to base credentials with a usageScanError field rather than failing the whole call
  • Default behavior unchanged: omit the flag and no extra API calls happen

Discover Schema

javascript
n8n_manage_credentials({
  action: "getSchema",
  type: "httpHeaderAuth"
})
// → Required fields, types, descriptions for this credential type

Create Credential

javascript
n8n_manage_credentials({
  action: "create",
  name: "My Slack Token",
  type: "slackApi",
  data: {accessToken: "xoxb-your-token"}
})
// → Created credential (data field stripped from response)

Update Credential

javascript
n8n_manage_credentials({
  action: "update",
  id: "123",
  name: "Updated Slack Token",
  data: {accessToken: "xoxb-new-token"},
  type: "slackApi"  // Optional, some n8n versions require it
})
// → Updated credential (data field stripped from response)

Delete Credential

javascript
n8n_manage_credentials({action: "delete", id: "123"})

Typical Workflow: Set Up Credentials for a New Integration

javascript
// 1. Discover what fields are needed
n8n_manage_credentials({
  action: "getSchema",
  type: "slackApi"
})

// 2. Create the credential
n8n_manage_credentials({
  action: "create",
  name: "Production Slack",
  type: "slackApi",
  data: {accessToken: "xoxb-..."}
})

// 3. Verify it was created
n8n_manage_credentials({action: "list"})

Typical Workflow: Safely Delete or Rotate a Credential

javascript
// 1. Check what would break
n8n_manage_credentials({action: "get", id: "123", includeUsage: true})
// → Inspect usedIn — the {id, name, active} of every workflow that references it

// 2a. If nothing depends on it, delete
n8n_manage_credentials({action: "delete", id: "123"})

// 2b. If something does, rotate the secret instead and notify owners
n8n_manage_credentials({
  action: "update",
  id: "123",
  data: {accessToken: "xoxb-new-..."}
})

Security Notes

  • Response stripping: get, create, and update all strip the data field from responses (defense-in-depth — secrets are never returned)
  • Log redaction: Credential request bodies are redacted from debug logs
  • Fallback resilience: get falls back to list+filter when GET /credentials/:id returns 403/405 (endpoint not in all n8n versions)
  • Usage scan resilience: when includeUsage: true triggers a workflow scan that fails, the response includes usageScanError and still returns the base credentials rather than erroring out

n8n_audit_instance (SECURITY AUDIT)

Speed: 500-5000ms (scans all workflows)

Use when: Auditing instance security, finding hardcoded secrets, checking for unauthenticated webhooks, verifying error handling

Two Scanning Approaches

1. Built-in Audit (via n8n's POST /audit API):

  • 5 risk categories: credentials, database, nodes, instance, filesystem
  • Wraps n8n's native audit endpoint; gracefully degrades if unavailable

2. Custom Deep Scan (workflow analysis):

  • hardcoded_secrets — 50+ regex patterns for API keys/tokens/passwords plus PII detection
  • unauthenticated_webhooks — Webhook/form triggers without authentication
  • error_handling — Workflows with 3+ nodes and no error handling
  • data_retention — Workflows saving all execution data

Examples

javascript
// Full audit (default)
n8n_audit_instance()

// Built-in audit only
n8n_audit_instance({
  categories: ["credentials", "nodes", "instance"],
  includeCustomScan: false
})

// Custom scan only — specific checks
n8n_audit_instance({
  customChecks: ["hardcoded_secrets", "unauthenticated_webhooks"]
})

// Custom abandoned workflow threshold
n8n_audit_instance({
  daysAbandonedWorkflow: 90
})

Output

Returns an actionable markdown report with:

  • Summary table: Critical/high/medium/low finding counts
  • Findings by workflow: Per-workflow tables of issues
  • Built-in audit results: n8n's native audit findings
  • Remediation Playbook:
    • Auto-fixable items (with tool chains to apply)
    • Items requiring review (human judgment needed)
    • Items requiring user action (e.g., key rotation)

Secret Masking

Detected secrets are masked in output — shows first 6 + last 4 characters only. Raw values are never stored or returned.

Remediation Types

  • auto_fixable — Can be fixed with MCP tools (e.g., add webhook auth)
  • review_recommended — Needs human judgment (e.g., PII detection)
  • user_input_needed — Requires user decision (e.g., choose auth method)
  • user_action_needed — Manual action required (e.g., rotate exposed API key)

n8n_validate_workflow (by ID)

Use when: Validating workflow stored in n8n

javascript
n8n_validate_workflow({
  id: "workflow-id",
  options: {
    validateNodes: true,
    validateConnections: true,
    validateExpressions: true,
    profile: "runtime"
  }
})

n8n_get_workflow

Use when: Retrieving workflow details

n8n has a draft/publish model: the workflow body holds the draft (your latest edits), while mode: "active" returns the published graph that's actually running. Pick the mode by how much you need and how big the workflow is.

Modes:

  • full (default) - Draft workflow JSON + metadata
  • details - Full + execution stats (success/error counts, last run)
  • active - The published (running) graph; returns code: "NO_ACTIVE_VERSION" if the workflow was never activated
  • structure - Nodes + connections only (topology, no parameters)
  • filtered - Full config of only the nodes named in nodeNames (matched by node name or node id), plus light metadata. Use it to read one heavy node — e.g. a Code node with long jsCode/pythonCode — on a large workflow that would otherwise get truncated client-side when fetched whole
  • minimal - ID, name, active, tags (fastest)
javascript
// Full draft workflow
n8n_get_workflow({id: "workflow-id"})

// Just the topology (cheap; strips parameters)
n8n_get_workflow({id: "workflow-id", mode: "structure"})

// Read one heavy node without the whole workflow (avoids client-side truncation)
n8n_get_workflow({id: "workflow-id", mode: "filtered", nodeNames: ["Process Data"]})

// Minimal metadata
n8n_get_workflow({id: "workflow-id", mode: "minimal"})

Recommended flow for big workflows: mode: "structure" to discover node names cheaply → mode: "filtered" with those names to pull the specific heavy node's full config. This is the fix for the case where full/active returns a payload large enough that the client truncates it and you can't read the Code-node source at all.

filtered mode returns: { id, name, active, isArchived, nodes[] (full config of matched nodes only), nodeCount (total in workflow), returnedCount, notFound? }. It omits connections and the rest of the graph by design, so the response stays small.

filtered pitfalls:

  • Requires a non-empty nodeNames array. Entries that match nothing come back in a notFound list rather than erroring, so a partial request stays transparent — check notFound before assuming a node is missing.
  • nodeNames matches each entry against node name OR id in one namespace, so returnedCount can exceed nodeNames.length when a name collides with another node's id, or when the workflow has duplicate node names. Disambiguate by the id on each returned node.

n8n_executions (EXECUTION MANAGEMENT)

Use when: Managing workflow executions

Get Execution Details

javascript
n8n_executions({
  action: "get",
  id: "execution-id",
  mode: "summary"  // preview, summary, filtered, full, error
})

// Error mode for debugging
n8n_executions({
  action: "get",
  id: "execution-id",
  mode: "error",
  includeStackTrace: true
})

List Executions

javascript
n8n_executions({
  action: "list",
  workflowId: "workflow-id",
  status: "error",  // success, error, waiting
  limit: 100
})

Delete Execution

javascript
n8n_executions({
  action: "delete",
  id: "execution-id"
})

n8n_evaluations (EVALUATION TEST RUNS)

Use when: Reading evaluation test runs — polling a run started in the editor, comparing metrics across runs, pulling per-case results into a report or dashboard.

Read-only. Requires n8n >= 2.30 and an API key created on 2.30+ — keys created earlier silently lack the testRun scopes, so a 403 means "re-create the API key", not a bug. Runs exist only for workflows with an evaluation trigger that have been run from the n8n editor; triggering runs via the public API is not yet supported by n8n (planned upstream, will arrive as run/cancel actions).

List Test Runs

javascript
n8n_evaluations({
  action: "list_runs",
  workflowId: "workflow-id",
  status: "completed"  // new, running, completed, error, cancelled
})

Get a Run (aggregated metrics)

javascript
n8n_evaluations({
  action: "get_run",
  workflowId: "workflow-id",
  runId: "run-id"
})
// → status, finalResult (success/error/warning), metrics, testCaseCount
// metrics is a flat name → number/boolean map: your custom metrics plus
// n8n's automatic ones (promptTokens, completionTokens, totalTokens, executionTime)

Per-Case Results

javascript
n8n_evaluations({
  action: "list_cases",
  workflowId: "workflow-id",
  runId: "run-id"
})
// Default limit 20 — per-case inputs/outputs can be large; paginate with
// cursor rather than raising the limit.
// Each case carries an executionId — drill into the underlying execution
// with n8n_executions({action: "get", id: executionId, mode: "error"})

Gotchas:

  • A 404 can mean three things: the instance predates 2.30, the workflowId is wrong, or the runId belongs to a different workflow (the tool's error message disambiguates using the instance version)
  • Evaluations are license/quota-gated in n8n — an instance without the feature simply has no runs
  • Compare metrics across runs of the same workflow to catch prompt/model regressions

Workflow Lifecycle

Standard pattern:

1. CREATE
   n8n_create_workflow({...})
   → Returns workflow ID

2. VALIDATE
   n8n_validate_workflow({id})
   → Check for errors

3. EDIT (iterative! 56s avg between edits)
   n8n_update_partial_workflow({id, intent: "...", operations: [...]})
   → Make changes

4. VALIDATE AGAIN
   n8n_validate_workflow({id})
   → Verify changes

5. ACTIVATE
   n8n_update_partial_workflow({
     id,
     intent: "Activate workflow",
     operations: [{type: "activateWorkflow"}]
   })
   → Workflow now runs on triggers!

6. MONITOR
   n8n_executions({action: "list", workflowId: id})
   n8n_executions({action: "get", id: execution_id})

Common Patterns from Telemetry

Pattern 1: Edit → Validate (7,841 occurrences)

javascript
n8n_update_partial_workflow({...})
// ↓ 23s (thinking about what to validate)
n8n_validate_workflow({id})

Pattern 2: Validate → Fix (7,266 occurrences)

javascript
n8n_validate_workflow({id})
// ↓ 58s (fixing errors)
n8n_update_partial_workflow({...})

Pattern 3: Iterative Building (31,464 occurrences)

javascript
update → update → update → ... (56s avg between edits)

This shows: Workflows are built iteratively, not in one shot!


Best Practices

Do

  • Build workflows iteratively (avg 56s between edits)
  • Include intent parameter for better responses
  • Use smart parameters (branch, case) for clarity
  • Validate after significant changes
  • Use atomic mode (default) for critical updates
  • Specify sourceOutput for AI connections
  • Clean stale connections after node renames/deletions
  • Use n8n_deploy_template for quick starts
  • Activate workflows via API when ready

Don't

  • Try to build workflows in one shot
  • Skip the intent parameter
  • Use sourceIndex when branch/case available
  • Skip validation before activation
  • Forget to test workflows after creation
  • Ignore auto-sanitization behavior

Summary

Most Important:

  1. n8n_update_partial_workflow is most-used tool (38,287 uses, 19 operation types)
  2. Include intent parameter for better responses
  3. Workflows built iteratively (56s avg between edits)
  4. Use smart parameters (branch="true", case=0) for clarity
  5. patchNodeField for surgical string edits (strict find/replace with regex support)
  6. AI connections supported (8 types with sourceOutput)
  7. Workflow activation supported via API (activateWorkflow operation)
  8. Auto-sanitization runs on all operations
  9. Use n8n_deploy_template for quick starts

Additional Tools:

  • n8n_deploy_template - Deploy templates directly
  • n8n_workflow_versions - Version control & rollback
  • n8n_test_workflow - Trigger execution
  • n8n_executions - Manage executions
  • n8n_evaluations - Read evaluation test runs (n8n 2.30+, read-only)
  • n8n_manage_datatable - Data table and row management
  • n8n_manage_credentials - Credential CRUD + schema discovery
  • n8n_audit_instance - Security audit (built-in + custom scan)
  • n8n_delete_workflow - Permanently delete workflows
  • n8n_list_workflows - List workflows with filtering
  • n8n_update_full_workflow - Full workflow replacement

Related: