{
  "nodes": [
    {
      "id": "1ec9d39f-9335-4e20-972c-8973b1e450c0",
      "name": "Route by Action",
      "type": "n8n-nodes-base.switch",
      "position": [
        528,
        352
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "active_workflows",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "74630646-16e0-4070-a3af-a0dd3c851248",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.action }}",
                    "rightValue": "get_active_workflows"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "executions_worfklows",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "b5d83172-406e-4b65-b6e2-9aa82e52656d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.action }}",
                    "rightValue": "get_workflow_executions"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "execution_details",
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "d473b358-fada-49a2-9221-c35d1675f944",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.body.action }}",
                    "rightValue": "get_execution_details"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "notesInFlow": true,
      "typeVersion": 3
    },
    {
      "id": "5559b642-a02d-4d46-8894-63445b559e21",
      "name": "Extract All Executions",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1008,
        112
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "cf916e3a-d789-412b-bf3e-881e6d695a33",
      "name": "Get Last Executions",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        800,
        112
      ],
      "parameters": {
        "url": "=https://<YOUR_N8N_INSTANCE>/api/v1/executions",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "includeData",
              "value": "={{false}}"
            },
            {
              "name": "limit",
              "value": "={{ $('Webhook').item.json.body.limit }}"
            }
          ]
        },
        "nodeCredentialType": "n8nApi"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "e62f6ce2-e4f4-4553-8d53-1c2f27bf3311",
      "name": "Get Active Workflows",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        816,
        336
      ],
      "parameters": {
        "url": "=https://<YOUR_N8N_INSTANCE>/api/v1/workflows",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "active",
              "value": "={{true}}"
            },
            {
              "name": "limit",
              "value": "={{ $('Webhook').item.json.body.workflow_id }}"
            },
            {
              "name": "excludePinnedData",
              "value": "={{true}}"
            }
          ]
        },
        "nodeCredentialType": "n8nApi"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "fea23566-d005-47b5-ba42-253b057c88cb",
      "name": "Active Workflows",
      "type": "n8n-nodes-base.set",
      "position": [
        1264,
        336
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d15f58d4-551d-423d-bae7-19e7b8d9f58d",
              "name": "createdAt",
              "type": "string",
              "value": "={{ $json.createdAt }}"
            },
            {
              "id": "37bff539-0f27-4f40-8235-789910e8c5f8",
              "name": "updatedAt",
              "type": "string",
              "value": "={{ $json.updatedAt }}"
            },
            {
              "id": "29d013e7-127b-41ec-ab1d-4deef3c040f4",
              "name": "id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "aee15b56-0237-45cf-8a29-f5d24eb7db15",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "78d99983-8baa-4b07-b357-bcc7a0ecfa4d",
              "name": "isArchived",
              "type": "string",
              "value": "={{ $json.isArchived }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "7c1725b9-0fbd-426e-945c-191d00736d0a",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        368,
        368
      ],
      "parameters": {
        "path": "8d8ea5d4-986e-46f3-adee-11eda64f8f60",
        "options": {
          "rawBody": false
        },
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "09540d94-9ffa-433e-88ab-b902e3a74349",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1488,
        368
      ],
      "parameters": {
        "options": {},
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.4
    },
    {
      "id": "0f2be966-7ca7-4c40-9131-e8f8d5559c5d",
      "name": "Get Executions Details (Status = Error)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        800,
        576
      ],
      "parameters": {
        "url": "=https://<YOUR_N8N_INSTANCE>/api/v1/executions",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "includeData",
              "value": "={{true}}"
            },
            {
              "name": "limit",
              "value": "={{ $('Webhook').item.json.body.limit }}"
            },
            {
              "name": "workflowId",
              "value": "={{ $('Webhook').item.json.body.workflow_id }}"
            },
            {
              "name": "status",
              "value": "error"
            }
          ]
        },
        "nodeCredentialType": "n8nApi"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "4c3e3613-c4dc-417e-9db7-0656e1a7ff51",
      "name": "Processing Audit",
      "type": "n8n-nodes-base.code",
      "position": [
        1264,
        112
      ],
      "parameters": {
        "jsCode": "const executions = $input.all().map(item => item.json);\n\n// Basic metrics \nconst totalExecutions = executions.length;\nconst failedExecutions = executions.filter(exec => exec.status === 'error');\nconst successfulExecutions = executions.filter(exec => exec.status === 'success');\nconst failedCount = failedExecutions.length;\nconst successCount = successfulExecutions.length;\nconst failureRate = totalExecutions > 0 ? ((failedCount / totalExecutions) * 100).toFixed(2) : 0;\n\n// All the unique workflows that had failures\nconst workflowsWithFailures = [...new Set(failedExecutions.map(exec => exec.workflowId))];\nconst workflowsWithFailuresCount = workflowsWithFailures.length;\n\n// Group failed executions by workflow\nconst failedByWorkflow = {};\nfailedExecutions.forEach(exec => {\n  if (!failedByWorkflow[exec.workflowId]) {\n    failedByWorkflow[exec.workflowId] = {\n      workflowId: exec.workflowId,\n      failures: [],\n      failureCount: 0\n    };\n  }\n  failedByWorkflow[exec.workflowId].failures.push({\n    id: exec.id,\n    startedAt: exec.startedAt,\n    stoppedAt: exec.stoppedAt,\n    mode: exec.mode\n  });\n  failedByWorkflow[exec.workflowId].failureCount++;\n});\n\n// Calculate execution modes distribution\nconst executionModes = executions.reduce((acc, exec) => {\n  acc[exec.mode] = (acc[exec.mode] || 0) + 1;\n  return acc;\n}, {});\n\n// Get all unique workflows\nconst allWorkflows = [...new Set(executions.map(exec => exec.workflowId))];\nconst totalWorkflowsExecuted = allWorkflows.length;\n\n// Metrics per workflow\nconst workflowMetrics = {};\nallWorkflows.forEach(workflowId => {\n  const workflowExecs = executions.filter(exec => exec.workflowId === workflowId);\n  const workflowFailed = workflowExecs.filter(exec => exec.status === 'error').length;\n  const workflowSuccess = workflowExecs.filter(exec => exec.status === 'success').length;\n  \n  workflowMetrics[workflowId] = {\n    workflowId: workflowId,\n    totalExecutions: workflowExecs.length,\n    successfulExecutions: workflowSuccess,\n    failedExecutions: workflowFailed,\n    successRate: workflowExecs.length > 0 ? \n      ((workflowSuccess / workflowExecs.length) * 100).toFixed(2) + '%' : '0%',\n    failureRate: workflowExecs.length > 0 ? \n      ((workflowFailed / workflowExecs.length) * 100).toFixed(2) + '%' : '0%',\n    lastExecution: workflowExecs[0]?.startedAt || null,\n    executionModes: workflowExecs.reduce((acc, exec) => {\n      acc[exec.mode] = (acc[exec.mode] || 0) + 1;\n      return acc;\n    }, {})\n  };\n});\n\n// Sort workflows by failure rate (highest rate first)\nconst workflowsByFailureRate = Object.values(workflowMetrics)\n  .sort((a, b) => parseFloat(b.failureRate) - parseFloat(a.failureRate))\n  .slice(0, 10); // Top 10 problematic workflows\n\n// Calculate time-based metrics\nconst now = new Date();\nconst executionsByHour = {};\n\nexecutions.forEach(exec => {\n  const startTime = new Date(exec.startedAt);\n  const hourKey = startTime.toISOString().slice(0, 13) + ':00'; // Round to hour\n  \n  if (!executionsByHour[hourKey]) {\n    executionsByHour[hourKey] = {\n      total: 0,\n      success: 0,\n      error: 0\n    };\n  }\n  \n  executionsByHour[hourKey].total++;\n  if (exec.status === 'success') {\n    executionsByHour[hourKey].success++;\n  } else if (exec.status === 'error') {\n    executionsByHour[hourKey].error++;\n  }\n});\n\n// Calculate average execution time for finished executions\nconst executionTimes = executions\n  .filter(exec => exec.finished && exec.startedAt && exec.stoppedAt)\n  .map(exec => {\n    const start = new Date(exec.startedAt);\n    const stop = new Date(exec.stoppedAt);\n    return (stop - start) / 1000; // ms to seconds\n  });\n\nconst avgExecutionTime = executionTimes.length > 0 \n  ? (executionTimes.reduce((a, b) => a + b, 0) / executionTimes.length).toFixed(2)\n  : 0;\n\nconst maxExecutionTime = executionTimes.length > 0 \n  ? Math.max(...executionTimes).toFixed(2)\n  : 0;\n\nconst minExecutionTime = executionTimes.length > 0 \n  ? Math.min(...executionTimes).toFixed(2)\n  : 0;\n\n// Find most recent failures\nconst recentFailures = failedExecutions\n  .sort((a, b) => new Date(b.startedAt) - new Date(a.startedAt))\n  .slice(0, 5)\n  .map(exec => ({\n    id: exec.id,\n    workflowId: exec.workflowId,\n    startedAt: exec.startedAt,\n    mode: exec.mode\n  }));\n\n// Return all indicators\nconst kpis = {\n  summary: {\n    totalExecutions: totalExecutions,\n    successfulExecutions: successCount,\n    failedExecutions: failedCount,\n    failureRate: failureRate + '%',\n    successRate: (100 - parseFloat(failureRate)).toFixed(2) + '%',\n    totalWorkflowsExecuted: totalWorkflowsExecuted,\n    workflowsWithFailures: workflowsWithFailuresCount\n  },\n  \n  executionModes: executionModes,\n  \n  timing: {\n    averageExecutionTime: avgExecutionTime + ' seconds',\n    maxExecutionTime: maxExecutionTime + ' seconds',\n    minExecutionTime: minExecutionTime + ' seconds',\n    timeRange: {\n      from: executions[executions.length - 1]?.startedAt || null,\n      to: executions[0]?.startedAt || null\n    }\n  },\n  \n  failureAnalysis: {\n    workflowsImpactedByFailures: workflowsWithFailures,\n    failedExecutionsByWorkflow: failedByWorkflow,\n    recentFailures: recentFailures\n  },\n  \n  workflowPerformance: {\n    allWorkflowMetrics: workflowMetrics,\n    topProblematicWorkflows: workflowsByFailureRate\n  },\n  \n  timeSeriesData: executionsByHour,\n  \n  alerts: {\n    highFailureRate: parseFloat(failureRate) > 10,\n    failureRateThreshold: parseFloat(failureRate) > 10 ? \n      `\u26a0\ufe0f High failure rate detected: ${failureRate}%` : \n      `\u2705 Failure rate within acceptable range: ${failureRate}%`,\n    workflowsNeedingAttention: Object.values(workflowMetrics)\n      .filter(wf => parseFloat(wf.failureRate) > 20)\n      .map(wf => ({\n        workflowId: wf.workflowId,\n        failureRate: wf.failureRate,\n        failedCount: wf.failedExecutions\n      }))\n  }\n};\n\n// Return the KPIs object\nreturn kpis;"
      },
      "typeVersion": 2
    },
    {
      "id": "8d02bd44-4501-4441-a542-01093173f008",
      "name": "Split Active Executions",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1040,
        336
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "1ae4ac25-bcff-4849-8156-657daa906c91",
      "name": "Details of Executions",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1232,
        576
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "0f33a4c0-9a30-43f4-89fe-f55c9462a7eb",
      "name": "Video Tutorial",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        48
      ],
      "parameters": {
        "color": 4,
        "width": 464,
        "height": 304,
        "content": "## [Tutorial](https://www.youtube.com/watch?v=oJzNnHIusZs)\n@[youtube](oJzNnHIusZs)"
      },
      "typeVersion": 1
    },
    {
      "id": "7d9ba773-3711-47e2-bedf-69b8da24a0ae",
      "name": "Main Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -128,
        48
      ],
      "parameters": {
        "width": 464,
        "height": 680,
        "content": "## Workflow Monitoring Endpoint \n\n### How it works\nThis workflow, combined with a local MCP Server will help you to monitor any n8n instance health through API endpoints. \n\nBased on the action selected in the body request received by the webhook, it triggers different queries to get **execution metrics**, **workflow statuses**, and **failure analysis**. \n- `get_active_workflows` \u2192 List all active workflows\n- `get_workflow_executions` \u2192 Fetch the latest workflow runs \n- `get_execution_details` \u2192 Retrieve all failed executions for a workflow\n\n### Setup steps  \n- [ ] Replace `<YOUR_N8N_INSTANCE>` in all HTTP nodes with your instance URL\n- [ ] Configure n8n API credentials for authentication  \n- [ ] Set `limit` and `workflow_id` in request body as needed\n- [ ] Set up the local MCP Server following the instructions of the tutorial\n\n### Customization\nYou can modify the `Processing Audit` node to adjust failure thresholds (currently set at 10% triggers alerts) or add custom KPIs for your monitoring needs.\n\n*If you have any question, feel to leave a comment in the video!*"
      },
      "typeVersion": 1
    },
    {
      "id": "3cb68d76-5bec-4aa7-8b00-59282d35726d",
      "name": "Webhook Entry",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 304,
        "height": 684,
        "content": "## 1. Webhook Entry with a switch by action\nReceives POST requests with action parameter to route monitoring requests"
      },
      "typeVersion": 1
    },
    {
      "id": "ac9aa151-073f-408d-9860-e3ca44e85dec",
      "name": "API Calls",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 712,
        "height": 200,
        "content": "## 2. Get last executions logs and process them"
      },
      "typeVersion": 1
    },
    {
      "id": "b6bda9de-3551-4542-9e09-3330e4dba149",
      "name": "Response",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 166,
        "height": 684,
        "content": "## 5. Send Response back"
      },
      "typeVersion": 1
    },
    {
      "id": "099c044d-9d6d-488c-bde1-3caa08ba3dec",
      "name": "API Calls1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        288
      ],
      "parameters": {
        "color": 7,
        "width": 712,
        "height": 200,
        "content": "## 3. Get all the active workflows of the instance"
      },
      "typeVersion": 1
    },
    {
      "id": "7c416a84-6e5d-4f96-ba65-08475737bec7",
      "name": "API Calls2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        512
      ],
      "parameters": {
        "color": 7,
        "width": 696,
        "height": 216,
        "content": "## 4. Get the detailed executions logs for a specific workflow "
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Route by Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Action": {
      "main": [
        [
          {
            "node": "Get Active Workflows",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Last Executions",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Executions Details (Status = Error)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Active Workflows": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Processing Audit": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Executions": {
      "main": [
        [
          {
            "node": "Extract All Executions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Active Workflows": {
      "main": [
        [
          {
            "node": "Split Active Executions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Details of Executions": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract All Executions": {
      "main": [
        [
          {
            "node": "Processing Audit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Active Executions": {
      "main": [
        [
          {
            "node": "Active Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Executions Details (Status = Error)": {
      "main": [
        [
          {
            "node": "Details of Executions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}