n8n-lint
Provides tools for linting n8n workflow exports, detecting reliability issues such as missing error workflows, HTTP requests without retries, retries that swallow errors, unauthenticated webhooks, hardcoded secrets, disabled nodes, default node names, and orphan nodes. It returns machine-readable findings with one-line fixes for each issue.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@n8n-lintlint this n8n workflow export and list any reliability issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-n8n-lint
An MCP (Model Context Protocol) server that lints n8n workflow exports for reliability problems: missing error workflows, HTTP calls without retries, retries that swallow errors, unauthenticated webhooks, hardcoded secrets, and a few readability issues.
It reads the exported workflow JSON only. It is deterministic, needs no network access and never calls the n8n API, so it is safe to run on exports you do not want to send anywhere.
Why an MCP server: an AI agent that builds or reviews n8n workflows can call lint_workflow after every change and get machine-readable findings with a one-line fix for each, instead of guessing what "reliable" means.
Install and run
Requires Node.js 20 or newer.
npm install
npm run build
npm test # builds, then runs the vitest suiteThe server speaks MCP over stdio. Run it directly with node dist/index.js, or register it in a client.
Claude Code
claude mcp add n8n-lint -- node /absolute/path/to/mcp-n8n-lint/dist/index.jsAny MCP client (JSON config)
{
"mcpServers": {
"n8n-lint": {
"command": "node",
"args": ["/absolute/path/to/mcp-n8n-lint/dist/index.js"]
}
}
}Related MCP server: n8n-ops-mcp
Tools
Tool | Input | Output |
|
|
|
| none |
|
|
|
|
Bad input (invalid JSON, no nodes array, unknown rule id) is returned as an MCP tool error, not a crash. The error text never quotes the input.
Rules
Id | Name | Severity | What it checks |
R001 | no-error-workflow | warning |
|
R002 | http-no-retry | warning | An |
R003 | retry-with-continue | warning |
|
R004 | webhook-no-auth | warning | An |
R005 | hardcoded-secret | error | A node parameter that looks like a secret: a Bearer token, an |
R006 | disabled-node | info | A node with |
R007 | default-node-name | info | A node still named like its default ( |
R008 | orphan-node | warning | A node (not a trigger, not a sticky note) with no incoming and no outgoing connection. |
R005 never prints the value it found. Findings contain only the parameter path and the kind of match, with the value replaced by ********. Tests plant fake secrets in fixtures and assert that no part of them appears in any output.
Example
Input to lint_workflow (a small workflow with a fake placeholder token):
{
"name": "Order intake",
"nodes": [
{
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": { "httpMethod": "POST", "path": "orders" },
"position": [0, 0]
},
{
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.example.invalid/orders",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "Authorization", "value": "Bearer fake-bearer-token-0000000000000000" }
]
}
},
"position": [200, 0]
}
],
"connections": {
"Webhook": { "main": [[{ "node": "HTTP Request", "type": "main", "index": 0 }]] }
},
"settings": { "executionOrder": "v1" }
}Output:
{
"summary": { "error": 1, "warning": 3, "info": 1, "total": 5 },
"findings": [
{
"ruleId": "R005",
"severity": "error",
"node": "HTTP Request",
"message": "Parameter \"parameters.headerParameters.parameters[0].value\" looks like a hardcoded secret (literal value of \"Authorization\" header/field): ********",
"fix": "Rotate the secret and move it into an n8n credential; clear \"parameters.headerParameters.parameters[0].value\"."
},
{
"ruleId": "R001",
"severity": "warning",
"node": null,
"message": "No error workflow is configured (settings.errorWorkflow is missing or empty).",
"fix": "Set an error workflow (one that starts with an Error Trigger node) in Workflow Settings."
},
{
"ruleId": "R002",
"severity": "warning",
"node": "HTTP Request",
"message": "HTTP Request node has no retries (retryOnFail is not true).",
"fix": "Turn on Retry On Fail for this node and set Max Tries and Wait Between Tries."
},
{
"ruleId": "R004",
"severity": "warning",
"node": "Webhook",
"message": "Webhook node does not require authentication.",
"fix": "Set Authentication to Basic auth, Header auth or JWT auth on this node."
},
{
"ruleId": "R007",
"severity": "info",
"node": "HTTP Request",
"message": "Node uses a default name (\"HTTP Request\").",
"fix": "Rename the node to describe what it does."
}
]
}How the n8n field names were checked
Field names were checked against docs.n8n.io (October 2026):
Confirmed in the Public API schema for the workflow and node objects:
retryOnFail,maxTries,waitBetweenTries,onError,continueOnFail(marked deprecated, "use onError instead"),disabled,parameters,settings.errorWorkflow(the ID of the workflow that contains the Error Trigger node), andconnections(keyed by source node name).Confirmed in the n8n docs' reference for editing workflows with the n8n MCP tools (
setNodeSettings): theonErrorvaluesstopWorkflow,continueRegularOutput,continueErrorOutput.Confirmed by example workflows embedded in the docs: the node types
n8n-nodes-base.httpRequest,n8n-nodes-base.webhookandn8n-nodes-base.stickyNote, the default nameHTTP Request, and theconnectionsstructure ({ "<source>": { "main": [[ { "node", "type", "index" } ]] } }).Behavior: the Handle errors gracefully page says an error workflow "runs if an execution fails", and the node settings page says that On Error "Continue" proceeds despite the error. That is the basis for R001 and R003.
Pages used: Handle errors gracefully, Work with nodes, Webhook node, and the Public API reference.
Not confirmed by the documentation
These parts are based on observed export format, not documented. The rules are kept, and explain_rule repeats the note:
R004:
parameters.authenticationon the Webhook node, and the value"none". The docs list the options only by their UI labels (Basic auth, Header auth, JWT auth, None) and do not show the JSON key or values. The rule treats an absent key the same as"none", which is consistent with the documented example webhook (it has noauthenticationkey), but this is an inference.R007: default display names other than
HTTP Request(for exampleEdit Fields). The list in the code is incomplete.R008 (and R007): which node types count as triggers is decided by a type-name heuristic (type ends with
Trigger, pluswebhook,start,cron,interval).R002: the docs describe
retryOnFailas an optional boolean without stating its default. A missing field is treated asfalse.R005: not tied to an n8n field. It is a pattern heuristic.
Limitations
Heuristics, not proof. R005 will produce false positives (for example a long identifier that looks like base64, or a placeholder in a
tokenfield) and false negatives (secrets split across fields, encoded, or short). R007 and R008 depend on lists and naming conventions.Export formats change between n8n versions, and the rules only look at the fields listed above. Older exports, exports copied from the editor canvas (which have no
settings), and workflows from other tools may be read differently. Run it on a current export if results look off.Rules do not skip disabled nodes (R006 reports them, R002 to R005 and R008 still look at them), and R001 also flags a workflow that is itself an error handler (one that starts with an Error Trigger).
It reads one JSON document. It does not call the n8n API, check that the referenced error workflow exists, resolve credentials, run the workflow, or follow sub-workflows.
R002 says nothing about whether a call is safe to retry. Retrying non-idempotent requests (payments, emails) can cause duplicates.
It does not replace a human review. It finds a fixed set of common reliability problems, not logic errors.
Only the eight rules above exist.
Development
npm install
npm run build # tsc -> dist/
npm test # build + vitest (unit tests, fixture tests, end-to-end MCP client test)Layout: src/rules.ts holds the rules, src/secrets.ts the secret detection, src/lint.ts the runner, src/server.ts the MCP tools. Test fixtures in tests/fixtures are synthetic workflows written for this project; all keys in them are obviously fake. Each rule has a rNNN-bad.json that triggers only that rule and a rNNN-good.json that does not trigger it.
License
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Security scanner for n8n workflows + live MCP Trust-Check. 18 rules, OWASP mapped. Paid x402 API.
Know when your n8n workflows, URLs, and AI apps break, before your customers do.
Audit GitHub Actions workflows for script injection, unpinned actions and missing permissions.
Diagnose AI workflows for failure, security, and handoff risks — RED/AMBER/GREEN per node.
Related MCP Servers
- AlicenseBqualityCmaintenanceSafe MCP server and CLI tool for testing, scoring, and inspecting n8n workflows. Features 19 tools for workflow testing, execution traces, tiered scoring, and a built-in node catalog with 800+ node types. Designed with safety-first approach: no credential management, no secrets lifecycle, no auto-fix loops.191MIT
- AlicenseAqualityBmaintenanceProvides ops-focused n8n tools for MCP-compatible agents, enabling listing, inspecting, triggering, validating, managing tags, running security audits, and safely editing n8n workflows with auto-backup and confirm gates.2016 npm1MIT
- AlicenseNot gradedqualityCmaintenanceConverts natural language descriptions into validated, production-ready n8n workflows with automatic error fixing and architecture recommendations.29 npm22-
- AlicenseNot gradedqualityDmaintenanceStatically analyzes exported n8n automation workflows for security issues and returns structured findings.MIT