mcp-n8n-ops
by Redsf
README.md
# mcp-n8n-ops
[](https://github.com/Redsf/mcp-n8n-ops/actions/workflows/ci.yml)
[](https://www.python.org/)
[](LICENSE)
An [MCP](https://modelcontextprotocol.io) server for operating an n8n instance.
Ask an AI assistant what is failing, why, and since when — instead of clicking
through the executions list.
> **You:** Anything broken in n8n today?
>
> **Assistant:** *(calls `failing_workflows`)* Two workflows are failing.
> "Invoice sync" has 14 failures since yesterday 09:40, all
> `ECONNREFUSED talking to Google Sheets`. "Cart recovery" failed twice, both
> rate limits. The Sheets one looks like a credential or network problem, not
> a logic bug — the failures start abruptly and share one error.
**Read-only by default.** Tools that change state are not merely refused —
they are *absent from the tool list* unless you start the server with
`--allow-write`. A model cannot be talked into calling a tool it cannot see.
**Zero dependencies.** The MCP stdio transport is implemented directly, so this
runs on any Python 3.9+ with nothing installed — which is what you want for a
tool you drop onto the box next to n8n.
## Install
```bash
pip install git+https://github.com/Redsf/mcp-n8n-ops
```
> Not on PyPI yet, so install from git.
## Configure
Get an API key from n8n: **Settings → n8n API → Create an API key.**
### Claude Desktop / Claude Code
```json
{
"mcpServers": {
"n8n-ops": {
"command": "mcp-n8n-ops",
"env": {
"N8N_URL": "https://n8n.example.com",
"N8N_API_KEY": "n8n_api_..."
}
}
}
}
```
Add `"args": ["--allow-write"]` only if you want the assistant able to activate
and deactivate workflows. Read the [safety](#safety) section first.
### Any other MCP client
It speaks MCP over stdio:
```bash
N8N_URL=https://n8n.example.com N8N_API_KEY=n8n_api_... mcp-n8n-ops
```
## Tools
### Read (always available)
| Tool | Answers |
|---|---|
| `failing_workflows` | **Start here.** Which workflows are failing, ranked by failure count, each with a sample error and the time of the last failure. |
| `health_summary` | Instance overview: workflow count, how many active, recent error rate. |
| `list_executions` | Recent executions, filterable by status or workflow. |
| `get_execution` | One execution, including the actual error message. |
| `list_workflows` | Workflows with id, name, active state, node count, tags. |
| `get_workflow` | One workflow's summary, optionally its node list. |
### Write (only with `--allow-write`)
| Tool | Does |
|---|---|
| `set_workflow_active` | Activates or deactivates a workflow. |
There is deliberately **no delete tool**, and none is planned. Deleting a
workflow or an execution is not something an assistant should be able to do on
your behalf, whatever the flag says.
## Aggregation happens server-side
`failing_workflows` returns a small ranked answer, not 200 raw executions for
the model to tally:
```json
{
"failed_executions_examined": 16,
"distinct_workflows_failing": 2,
"workflows": [
{
"workflow_id": "1",
"workflow_name": "Invoice sync",
"failures": 14,
"last_failure": "2026-07-21T10:00:00Z",
"sample_error": "ECONNREFUSED talking to Google Sheets"
}
]
}
```
Counting in Python instead of in the model is faster, cheaper, and it does not
get the arithmetic wrong.
## Safety
This server is driven by a model, which changes what "safe defaults" means.
- **Read-only unless you opt in.** Write tools are hidden, not just blocked.
Asked for anyway, the server explains why rather than returning a bare
"unknown tool", so nobody wastes time hunting a typo.
- **No delete, at any privilege level.**
- **The API key is never returned.** It goes out in a header and never appears
in a tool result or an error message.
- **n8n failures are tool errors, not crashes.** An unreachable instance or a
bad key comes back as `isError` with a readable message, and the server keeps
serving. A dead n8n should not take down the assistant's session.
- **stdout carries protocol only.** All logging goes to stderr. Writing anything
else to stdout corrupts the JSON-RPC stream — the most common way a
hand-written MCP server breaks.
A read-only key is still a broad grant: it can read every workflow, including
node parameters. Give this server its own key, and revoke it when you are done.
## Verifying it works
The test suite drives the real protocol — handshake, notification handling,
malformed frames, tool dispatch — against a fake n8n, so it runs with no
instance and no network:
```bash
pip install -e ".[dev]"
pytest
```
CI additionally starts the compiled entry point as a subprocess against a stub
n8n HTTP server and drives it with real MCP messages over stdio, asserting the
handshake, the tool list, an aggregated diagnosis, and that a write tool is
refused in read-only mode.
## Why not the official MCP SDK?
The SDK requires Python 3.10+. This targets 3.9 so it runs on the long-lived
boxes n8n tends to live on, and stays dependency-free so `pip install` cannot
drag in a transitive CVE on a machine that has production credentials on it.
MCP's stdio transport is newline-delimited JSON-RPC 2.0 — small enough to
implement correctly and test exhaustively, which is what the suite does.
## Related
- [n8n-workflow-linter](https://github.com/Redsf/n8n-workflow-linter) — catch problems before deploy
- [agent-evals](https://github.com/Redsf/agent-evals) — check behaviour before users do
- [automation-roi-toolkit](https://github.com/Redsf/automation-roi-toolkit) — decide what to build
- [same-system-three-ways](https://github.com/Redsf/same-system-three-ways) — n8n vs Python vs TypeScript, measured
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues