21 deterministic validators ported from @n8n/workflow-sdk to pure JS, exposed as 5 MCP tools. Plug it into Claude or Cursor and your agent will know what's broken before it ships — no LLM round-trip, no hallucinated schemas.
Two use cases. AI agents that build workflows: validate before shipping. Humans debugging hand-built flows: same tool, paste & check.
Same input, same output. Always. No model variance, no token spend.
Pure JS, runs on Cloudflare Workers. No isolated-vm required.
Each tool returns structured, machine-readable output. No prose. No hedging. Connect once, then let your model rely on hard schema and pattern checks instead of best-effort reasoning.
Run all 21 validators on a workflow JSON. Returns errors and warnings with codes, severities, and exact parameter paths — not guesses, not ranges, exact nodes[3].parameters.url coordinates the agent can patch.
→ POST /validate { "errors": 3, "warnings": 2, "issues": [ { "code": "NODE_DISCONNECTED", "severity": "error", "path": "nodes[4]" }, … ] }
Fetch a workflow from a user-supplied n8n instance and validate it. Credentials passed per-call, never stored.
Returns the 66 types in the catalog with their available versions. Lets the LLM know which nodes have schema enforcement.
Returns canonical shape — inputs, outputs, properties with required/displayOptions/defaults — for a type+version.
When an agent generates a workflow, sticky notes can carry hostile instructions that target the next agent that reads it (or you). 12 heuristic regex patterns spot instruction overrides, system-role claims, credential dumps, jailbreak templates. Returns suspicionScore + flagged content + a safe / manual_review / block recommendation. Zero LLM tokens.
→ tools/call analyze_sticky_notes { "summary": { "suspiciousCount": 1, "maxSuspicionScore": 0.75, "recommendation": "manual_review" }, "notes": [{ "flags": [ "instruction_override", "system_role_claim" ], … }] }
A real round-trip: Claude pastes a workflow, hits the validator, gets back exact nodes[i].parameters.x coordinates, patches the field, re-validates. No guessing, no hallucinated schemas, no token-cost loop.
Validate this n8n workflow before I deploy it:
{ "name": "Hourly user sync", "nodes": [ { "name": "Schedule", "type": "n8n-nodes-base.scheduleTrigger", /* … */ }, { "name": "Fetch users", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "parameters": { "method": "GET" } }, { "name": "Save to DB", "type": "n8n-nodes-base.set", /* expression below */ } ], "connections": { /* … */ } }
I'll run it through the n8n-flow-auditor MCP server.
{ "name": "validate_workflow", "arguments": { "workflow": {...} } }
{ "valid": false, "errors": [ { "code": "MISSING_PARAMETER", "message": "Required parameter 'url' (string) missing in 'Fetch users'.", "nodeName": "Fetch users", "parameterPath": "nodes[1].parameters.url" } ], "warnings": [ { "code": "MISSING_EXPRESSION_PREFIX", "message": "Expression `{{ $json.userId }}` missing '=' prefix", "nodeName": "Save to DB", "parameterPath": "nodes[2].parameters.values.string[0].value" } ] }
Two issues. One blocks the deploy:
1. Error — Fetch users (HTTP node) is missing the required url parameter at nodes[1].parameters.url.
2. Warning — Save to DB uses {{ $json.userId }} without the = prefix; n8n won't evaluate it as an expression.
Patching both:
- "parameters": { "method": "GET" } + "parameters": { "method": "GET", "url": "https://api.example.com/users" } - "value": "{{ $json.userId }}" + "value": "={{ $json.userId }}"
Re-validating…
{ "valid": true, "errors": [], "warnings": [] }
Workflow is now valid. Both fixes were exact — the validator pointed at the precise field paths, no guessing required.
✓ ready to deployTry it on the example workflows below. Calls POST /validate directly from your browser — public endpoint, WAF rate-limited, no auth required for one-off checks.
The official SDK ships the trigger-detection primitives. Everything else — schema enforcement, hardcoded-credential heuristics, expression-syntax checks, edge-runtime compatibility — you'd build yourself. We did.
setSchemaBaseDirs()manual provider wiringnodeTypesProvideranalyze_sticky_notesisolated-vm needs native buildMISSING_EXPRESSION_PREFIX — a real bug the SDK silently ignores. Zero false positives.
Full schema reference in the OpenAPI docs.
Connect from Claude Desktop. Cursor and other MCP-aware clients use the same URL. First call opens GitHub OAuth in your browser; the 30-day token is cached after that.
Find or create the Claude Desktop config file. Same path on macOS and Linux; Windows uses %APPDATA%.
$ code ~/.claude/claude_desktop_config.json
Same URL across MCP-aware clients. The OAuth handshake fires on first call.
// ~/.claude/claude_desktop_config.json (macOS / Linux) // %APPDATA%\Claude\claude_desktop_config.json (Windows) { "mcpServers": { "n8n-flow-auditor": { "url": "https://n8n-auditor.automators.work/mcp" } } }
// ~/.cursor/mcp.json (or Cursor → Settings → MCP) { "mcpServers": { "n8n-flow-auditor": { "url": "https://n8n-auditor.automators.work/mcp" } } }
// ~/.continue/config.json // (under experimental.modelContextProtocolServers) { "experimental": { "modelContextProtocolServers": [{ "transport": { "type": "streamable-http", "url": "https://n8n-auditor.automators.work/mcp" } }] } }
// VS Code → Cline → MCP Servers panel // Or edit cline_mcp_settings.json directly: { "mcpServers": { "n8n-flow-auditor": { "url": "https://n8n-auditor.automators.work/mcp", "disabled": false } } }
Restart Claude Desktop. The first invocation opens GitHub for sign-in; authorize once and you're done.
// in Claude Desktop: › validate this n8n workflow: › { "nodes": [...], "connections": {...} } ✓ tool called: validate_workflow ✓ 3 issues surfaced
/mcp endpoint is gated by OAuth 2.1 self-hosted with GitHub as upstream IdP. First connection opens a browser; subsequent calls use a 30-day token automatically. The public /validate REST endpoint accepts unauthenticated calls but is rate-limited at the edge by Cloudflare WAF (10 req per 10s window per IP). Need higher quota? Authenticate over MCP for per-user limits.