{
  "id": "mcgjjHDuNvrSB6Ly",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Gate every AI write with a policy engine and audit log in an n8n MCP server",
  "tags": [],
  "nodes": [
    {
      "id": "896227b8-73f6-4006-94c7-5c9a8dff4978",
      "name": "Company Data MCP Server",
      "type": "@n8n/n8n-nodes-langchain.mcpTrigger",
      "position": [
        560,
        -624
      ],
      "parameters": {
        "path": "company-data",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "60cb7b86-dca3-4b86-b3d3-d15a6dacfce4",
      "name": "lookup_customer",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        0,
        -368
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Customers"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        },
        "descriptionType": "manual",
        "toolDescription": "Look up one customer record by name or account ID. Returns owner, tier, region and contact details. Use this before any write so you are acting on the right account."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "76a8ad26-f979-449c-a645-4d99c69f0207",
      "name": "check_order_status",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        208,
        -368
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Orders"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        },
        "descriptionType": "manual",
        "toolDescription": "Get the status, ship date and value of one order by its order ID."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "58d0096a-01da-4a69-8d84-7937fb496464",
      "name": "list_open_invoices",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        400,
        -368
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Invoices"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        },
        "descriptionType": "manual",
        "toolDescription": "List unpaid invoices for one customer, with amounts and due dates. Read only."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "7ffbc524-0a9a-4552-b451-3017e238f6c6",
      "name": "log_customer_note",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        640,
        -368
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select THIS workflow"
        },
        "description": "Record a note against a customer account. Goes through the policy gate: empty notes are refused, anything resembling a credential is redacted, and an identical note inside the same hour is rejected."
      },
      "typeVersion": 2.2
    },
    {
      "id": "cc9a2d84-1977-461c-aa04-3ac3d1c4ab7b",
      "name": "create_follow_up_task",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        848,
        -368
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select THIS workflow"
        },
        "description": "Create a follow-up task for a customer. Put a YYYY-MM-DD due date inside details. The policy gate refuses due dates in the past."
      },
      "typeVersion": 2.2
    },
    {
      "id": "92583d36-e869-4ead-bf35-996a37382241",
      "name": "draft_customer_email",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1040,
        -368
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select THIS workflow"
        },
        "description": "Draft a customer email in Gmail. It is only ever a DRAFT and is never sent. Put the recipient address inside details. The policy gate refuses addresses outside the allowed domains."
      },
      "typeVersion": 2.2
    },
    {
      "id": "2fc0af06-98ba-4f0e-965e-54f62ea32424",
      "name": "notify_account_manager",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        1248,
        -368
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select THIS workflow"
        },
        "description": "Post a message to the account team in Slack. The policy gate refuses an identical message inside the same hour, so a looping model cannot spam the channel."
      },
      "typeVersion": 2.2
    },
    {
      "id": "a3fb3efd-1a9f-4d88-8c85-ec772b2135e5",
      "name": "Guarded Action Runner",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        16,
        432
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "action"
            },
            {
              "name": "customer"
            },
            {
              "name": "details"
            },
            {
              "name": "requested_by"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "75f82061-88b4-4758-89f7-f9ade69246f0",
      "name": "Check the Policy",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        432
      ],
      "parameters": {
        "jsCode": "// ---- Edit these to match your business ----\nconst ALLOWED_EMAIL_DOMAINS = ['example.com'];   // empty array = allow any domain\nconst MAX_DETAILS_CHARS = 2000;\nconst REPEAT_WINDOW_MS = 60 * 60 * 1000;\nconst REQUIRED = {\n  log_note:    ['customer', 'details'],\n  create_task: ['customer', 'details'],\n  draft_email: ['customer', 'details'],\n  notify_team: ['details']\n};\n// -------------------------------------------\n\nconst inp = $json;\nconst action = String(inp.action || '').trim();\nconst customer = String(inp.customer || '').trim();\nconst requestedBy = String(inp.requested_by || '').trim() || 'unattributed';\nlet details = String(inp.details || '').trim();\nconst problems = [];\n\nif (!REQUIRED[action]) {\n  problems.push('Unknown action \"' + action + '\". This server only accepts: ' + Object.keys(REQUIRED).join(', ') + '.');\n} else {\n  REQUIRED[action].forEach(function (f) {\n    if (!String(inp[f] || '').trim()) problems.push('Missing required field: ' + f + '.');\n  });\n}\n\nif (details.length > MAX_DETAILS_CHARS) details = details.slice(0, MAX_DETAILS_CHARS);\n\n// Never let something that looks like a credential get written into your systems\nlet redactions = 0;\nconst secretPatterns = [/\\b(sk|pk)-[A-Za-z0-9]{16,}\\b/g, /\\bBearer\\s+[A-Za-z0-9._-]{16,}\\b/g, /\\b[A-Fa-f0-9]{32,}\\b/g];\nsecretPatterns.forEach(function (re) {\n  details = details.replace(re, function () { redactions++; return '[redacted]'; });\n});\n\nlet recipient = '';\nif (action === 'draft_email') {\n  const m = details.match(/[\\w.+-]+@[\\w-]+\\.[\\w.-]+/);\n  recipient = m ? m[0] : '';\n  if (!recipient) {\n    problems.push('draft_email needs a recipient address inside details.');\n  } else {\n    const domain = recipient.split('@')[1].toLowerCase();\n    if (ALLOWED_EMAIL_DOMAINS.length && ALLOWED_EMAIL_DOMAINS.indexOf(domain) === -1) {\n      problems.push('Refusing to draft to ' + domain + '. Add it to ALLOWED_EMAIL_DOMAINS if that is intended.');\n    }\n  }\n}\n\nlet dueDate = '';\nif (action === 'create_task') {\n  const d = details.match(/\\d{4}-\\d{2}-\\d{2}/);\n  dueDate = d ? d[0] : '';\n  if (dueDate && new Date(dueDate) < new Date(new Date().toDateString())) {\n    problems.push('Due date ' + dueDate + ' is in the past.');\n  }\n}\n\n// Stop the model repeating itself - a loop must not spam the team or the sheet\nconst state = $getWorkflowStaticData('global');\nstate.recent = (state.recent || []).filter(function (r) { return Date.now() - r.at < REPEAT_WINDOW_MS; });\nconst fingerprint = action + '|' + customer + '|' + details.slice(0, 120);\nif (state.recent.some(function (r) { return r.fp === fingerprint; })) {\n  problems.push('An identical ' + action + ' was already carried out within the last hour. Not repeating it.');\n}\n\nconst allowed = problems.length === 0;\nif (allowed) state.recent.push({ fp: fingerprint, at: Date.now() });\n\nreturn [{ json: {\n  allowed: allowed, action: action, customer: customer, requestedBy: requestedBy,\n  details: details, recipient: recipient, dueDate: dueDate, redactions: redactions,\n  reason: allowed ? 'Passed every policy check' : problems.join(' ')\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "b1509268-618e-454d-9bbf-332196e382bd",
      "name": "Allowed by Policy",
      "type": "n8n-nodes-base.if",
      "position": [
        496,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.allowed }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "1cd0a0be-eed9-49a6-bc8d-127d4553d8dc",
      "name": "Route the Action",
      "type": "n8n-nodes-base.switch",
      "position": [
        864,
        384
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "log_note"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "create_task"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "draft_email"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "notify_team"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "64d397ad-3350-4ba6-83d7-3ee71c19f992",
      "name": "Log the Note",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1104,
        80
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Notes"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "d4551f11-5bc3-47fa-af0e-e34c8126a167",
      "name": "Write the Audit Trail",
      "type": "n8n-nodes-base.googleSheets",
      "onError": "continueRegularOutput",
      "position": [
        1344,
        432
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "AI Audit Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "ae7ba47d-7ea7-4d44-969c-478941eb00c7",
      "name": "Create the Task",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1104,
        272
      ],
      "parameters": {
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Tasks"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "e37dbb6f-4caf-457d-b174-3c404d4f8ef8",
      "name": "Draft the Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1104,
        448
      ],
      "parameters": {
        "message": "={{ $json.details }}",
        "options": {
          "sendTo": "={{ $json.recipient }}"
        },
        "subject": "={{ \"Regarding your account - \" + $json.customer }}",
        "resource": "draft"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fa47a15f-3c18-4275-8c7e-25b8beb9f214",
      "name": "Notify the Team",
      "type": "n8n-nodes-base.slack",
      "position": [
        1104,
        624
      ],
      "parameters": {
        "text": "={{ \"*\" + $json.customer + \"* - requested by \" + $json.requestedBy + \"\\n\" + $json.details }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "#accounts"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "d8c23d16-ae56-41e9-b906-edb3727cf920",
      "name": "Answer the Model",
      "type": "n8n-nodes-base.code",
      "position": [
        1552,
        432
      ],
      "parameters": {
        "jsCode": "const p = $('Check the Policy').first().json;\n\nif (!p.allowed) {\n  return [{ json: { result: 'BLOCKED. ' + p.reason + ' Nothing was changed, and the refusal is in the audit log. Tell the user plainly what was refused and why. Do not retry with the same arguments.' } }];\n}\n\nconst done = {\n  log_note: 'A note was logged against ' + p.customer + '.',\n  create_task: 'A follow-up task was created for ' + p.customer + (p.dueDate ? ', due ' + p.dueDate : ', with no due date') + '.',\n  draft_email: 'A Gmail DRAFT was created for ' + p.recipient + '. It has NOT been sent - a person must open it, review it and send it.',\n  notify_team: 'The account team was notified in Slack.'\n};\n\nconst extra = p.redactions ? ' ' + p.redactions + ' value(s) that looked like credentials were redacted before writing.' : '';\nreturn [{ json: { result: (done[p.action] || 'Done.') + extra + ' Recorded in the audit log.' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "047a6e1e-3772-41a2-b2ac-d4f4188a0597",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -960,
        -736
      ],
      "parameters": {
        "width": 812,
        "height": 1560,
        "content": "## Gate every AI write with a policy engine and audit log in an n8n MCP server\n\n### Why this exists\nHooking an assistant up to your business systems is the easy part. The hard part is that the moment it can write, it can write anything - to anyone, twice, with whatever it hallucinated in the arguments. Most MCP servers hand over raw table access and hope.\n\nThis one puts a gate in front of every write, and writes down what happened either way.\n\n### How it works\nThe MCP trigger publishes seven tools to any MCP client - Claude Desktop, ChatGPT, Cursor, or an AI Agent in another n8n workflow.\n\nThe three read tools answer questions directly: look up a customer, check an order, list a customer unpaid invoices. They cannot change anything.\n\nThe four write tools do not touch your systems at all. Each one calls this same workflow back through its Execute Sub-workflow trigger, so every write - note, task, email draft, Slack message - funnels through one policy engine before anything happens.\n\nThat policy engine is a Code node you own and can read end to end. It refuses unknown actions and missing fields. It redacts anything shaped like an API key or bearer token before it can be written into your sheets. It refuses email drafts to domains outside your allow list. It refuses task due dates in the past. And it fingerprints each request in workflow static data, so a model stuck in a loop cannot log the same note or page the same channel twice within an hour.\n\nWhatever passes is routed to the real action. Emails are only ever drafted, never sent. Every attempt, allowed or refused, is appended to an audit sheet with the action, the customer, who asked for it, the verdict and the reason.\n\nFinally the model is told the truth about what happened: what was done, or exactly what was refused and why, and that a draft still needs a human. It is never left to assume a blocked write succeeded.\n\n### Setup\n1. Connect Google Sheets, Gmail and Slack, and create a Header Auth credential holding a long random token.\n2. In the four guarded tool nodes, set Workflow to THIS workflow so the gate can call itself.\n3. Point the tools at your spreadsheet. Tabs needed: Customers, Orders, Invoices, Notes, Tasks, AI Audit Log.\n4. Open Check the Policy and edit ALLOWED_EMAIL_DOMAINS and the limits at the top to match your business.\n5. Activate, copy the MCP URL from the trigger, and add it to your client with the same token header.\n\n### Customization tips\nAdd your own rules to the policy engine - a spend ceiling, a working-hours window, a block on named accounts. Add a new action with one Switch branch and one entry in REQUIRED. Remove any write tool you do not want the model to have at all."
      },
      "typeVersion": 1
    },
    {
      "id": "1a8f8aec-9d9c-44eb-b6fc-d2f51f69307f",
      "name": "S1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 1844,
        "height": 500,
        "content": "## 1. The MCP surface\nOne token-protected endpoint publishes seven tools. The three on the left only read - a customer record, an order, a customer unpaid invoices. The four on the right are writes, and none of them touches your systems directly: each calls this workflow back through the policy gate below."
      },
      "typeVersion": 1
    },
    {
      "id": "63a14488-7096-47d7-905f-795bc9864426",
      "name": "S2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -208
      ],
      "parameters": {
        "color": 7,
        "width": 900,
        "height": 1024,
        "content": "## 2. One gate every write must pass\nThe Code node is the whole point, and it is yours to read and edit. Unknown actions and missing fields are refused. Anything shaped like an API key is redacted before it can be written. Email drafts to domains outside your allow list are refused, as are due dates in the past. Repeat requests are fingerprinted in static data, so a looping model cannot log the same note or page the same channel twice within the hour."
      },
      "typeVersion": 1
    },
    {
      "id": "f7742df2-600a-460f-984a-97e972f96183",
      "name": "S3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        -208
      ],
      "parameters": {
        "color": 7,
        "width": 912,
        "height": 1024,
        "content": "## 3. Act, record, and tell the model the truth\nWhatever passes is routed to the real action - emails are drafted, never sent. Allowed or refused, every attempt is appended to the audit sheet with the verdict and the reason. The model is then handed a plain answer: what was done, or exactly what was blocked and why, so it never reports a refused write as a success."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "58918680-16b5-499e-a3dc-643ace62d1e9",
  "nodeGroups": [],
  "connections": {
    "Log the Note": {
      "main": [
        [
          {
            "node": "Write the Audit Trail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create the Task": {
      "main": [
        [
          {
            "node": "Write the Audit Trail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Draft the Email": {
      "main": [
        [
          {
            "node": "Write the Audit Trail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify the Team": {
      "main": [
        [
          {
            "node": "Write the Audit Trail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "lookup_customer": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Check the Policy": {
      "main": [
        [
          {
            "node": "Allowed by Policy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route the Action": {
      "main": [
        [
          {
            "node": "Log the Note",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create the Task",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Draft the Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify the Team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Allowed by Policy": {
      "main": [
        [
          {
            "node": "Route the Action",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Write the Audit Trail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "log_customer_note": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "check_order_status": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "list_open_invoices": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "draft_customer_email": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Guarded Action Runner": {
      "main": [
        [
          {
            "node": "Check the Policy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write the Audit Trail": {
      "main": [
        [
          {
            "node": "Answer the Model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create_follow_up_task": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "notify_account_manager": {
      "ai_tool": [
        [
          {
            "node": "Company Data MCP Server",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}