Skip to main content
Glama
hrjapp
by hrjapp
README.md
# HRJ n8n MCP

Local stdio MCP bridge for managing n8n from HRJ Agent.

This is the sanitized public version of the bridge built for a production VPS. It gives HRJ n8n tools without exposing n8n over the public internet and without putting API keys in your HRJ config.

## What it does

Exposes these MCP tools:

### Health & Info (Safe — Read Only)
| Tool | Description | Risk |
|------|-------------|------|
| `health` | Check n8n API reachability and Docker status | 🟢 Safe |
| `container_status` | Get Docker container status | 🟢 Safe |

### Workflows — Read (Safe)
| Tool | Description | Risk |
|------|-------------|------|
| `list_workflows` | List workflows, optionally filtered by active state | 🟢 Safe |
| `get_workflow` | Inspect one workflow with secret-bearing fields redacted | 🟢 Safe |
| `find_workflows` | Search workflow metadata by name, ID, or tag | 🟢 Safe |
| `export_workflow` | Fetch redacted workflow JSON for backup/review | 🟢 Safe |

### Workflows — Write (PROTECTED)
| Tool | Description | Risk | Protection |
|------|-------------|------|------------|
| `create_workflow` | Create a new workflow with name, nodes, and connections | 🟠 Write | Disabled by default |
| `update_workflow` | Update an existing workflow (partial updates supported) | 🟠 Write | Disabled by default |
| `delete_workflow` | Delete a workflow (irreversible, backup first!) | 🔴 Destructive | **Env + Human Token** |
| `activate_workflow` | Activate a workflow by ID | 🔴 Production | **Env + Human Token** |
| `deactivate_workflow` | Deactivate a workflow by ID | 🔴 Production | **Env + Human Token** |

### Executions (Safe — Read Only)
| Tool | Description | Risk |
|------|-------------|------|
| `list_executions` | List recent executions | 🟢 Safe |
| `get_execution` | Inspect one execution; payload data is off by default | 🟢 Safe |
| `recent_failures` | Recent failed/error executions | 🟢 Safe |

### Docker (Safe — Read Only)
| Tool | Description | Risk |
|------|-------------|------|
| `container_logs` | Docker logs with line-level redaction | 🟢 Safe |

## Security posture

- Stdio only. No HTTP server. No public port.
- API key is loaded from environment or a local dotenv file.
- `.env` is gitignored.
- Example config uses `REPLACE_ME`, never a real key.
- Tool responses redact obvious credential, token, secret, password, and authorization fields.
- Execution payload data is disabled by default in `get_execution`.
- **Write tools are disabled by default** — only read tools are enabled unless you explicitly enable them.
- **Destructive operations require human CLI confirmation** — tokens are generated via interactive script, not by AI.
- **Audit logging** — all write operations are logged to `~/.config/n8n-mcp/logs/audit.log` (append-only).
- Automatic retry on transient 5xx errors and connection failures.

### Tool enablement (recommended)

By default, **only read-only tools are enabled**. This follows the principle of least privilege — write tools must be explicitly enabled.

| Category | Tools | Default | Protection |
|----------|-------|---------|------------|
| Read | `health`, `list_*`, `get_*`, `find_*`, `export_*`, `container_*` | ✅ Enabled | None needed |
| Write | `create_workflow`, `update_workflow` | ❌ Disabled | Env flag |
| Destructive | `delete_workflow` | ❌ Disabled | **Env + Human Token** |
| Production | `activate_workflow`, `deactivate_workflow` | ❌ Disabled | **Env + Human Token** |

To enable write tools, add them to your HRJ config:

```yaml
mcp_servers:
  n8n:
    # ... basic config ...
    tools:
      default_enabled:
        - health
        - list_workflows
        - get_workflow
        - find_workflows
        - list_executions
        - get_execution
        - recent_failures
        - export_workflow
        - container_logs
        - container_status
      # Enable write tools only when needed:
      # - create_workflow
      # - update_workflow
      # - delete_workflow
      # - activate_workflow
      # - deactivate_workflow
```

### Destructive operations protection

For `delete_workflow`, `activate_workflow`, and `deactivate_workflow`, **two layers of protection** are required:

#### Layer 1: Environment variable (server-side)

Set in your `~/.config/n8n-mcp/env`:

```bash
# For delete operations (KEEP FALSE UNLESS NEEDED)
N8N_MCP_ALLOW_DELETE=false

# For activate/deactivate operations (KEEP FALSE UNLESS NEEDED)
N8N_MCP_ALLOW_ACTIVATE=false
```

**Important:** Only set these to `true` temporarily when you need to perform the operation, then set them back to `false`.

#### Layer 2: Human confirmation token (CLI)

Even with the env flag enabled, you must generate a confirmation token via the interactive CLI script:

```bash
# For delete
./scripts/confirm-action.sh delete 123

# For activate
./scripts/confirm-action.sh activate 123

# For deactivate
./scripts/confirm-action.sh deactivate 123
```

The script will:
1. Display a clear warning about the action
2. Ask you to type `YES` to confirm
3. Generate a time-limited token (120 seconds)
4. The MCP server consumes this token when you call the tool

**Why this is secure:**
- The token is generated by a **separate CLI process**, not by the AI
- The AI cannot generate tokens — it requires **interactive human input**
- Tokens expire after 120 seconds
- Tokens are single-use (deleted after validation)
- Tokens are stored with restrictive permissions (600)

#### Example workflow

```bash
# 1. Enable delete temporarily
export N8N_MCP_ALLOW_DELETE=true

# 2. Generate confirmation token (interactive)
./scripts/confirm-action.sh delete 123
# Type: YES

# 3. Use the MCP tool (token is consumed automatically)
# The AI calls: delete_workflow(workflow_id="123")

# 4. Disable delete immediately
export N8N_MCP_ALLOW_DELETE=false
```

#### Audit logging

All operations are logged to `~/.config/n8n-mcp/logs/audit.log`:

```json
{"action": "DELETE_BLOCKED", "workflow_id": "123", "timestamp": "2026-07-28T21:30:00+00:00", "reason": "N8N_MCP_ALLOW_DELETE=false"}
{"action": "TOKEN_VALIDATED", "workflow_id": "123", "timestamp": "2026-07-28T21:35:00+00:00", "action": "delete"}
{"action": "DELETE_WORKFLOW", "workflow_id": "123", "timestamp": "2026-07-28T21:35:01+00:00", "status": "success"}
```

The log file is **append-only** — entries cannot be deleted or modified without root access.

## Requirements

- Python 3.10+
- HRJ Agent with native MCP enabled
- n8n API key
- n8n reachable from the machine running HRJ, usually `http://127.0.0.1:5678`

## Install

```bash
git clone https://github.com/hrjapp/hrj-n8n-mcp.git
cd hrj-n8n-mcp
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
```

## Store your n8n key

Interactive helper:

```bash
./scripts/set-key.sh
```

Default output path:

```text
~/.config/n8n-mcp/env
```

Expected permissions:

```bash
stat -c '%a %U:%G %n' ~/.config/n8n-mcp/env
# 600 youruser:yourgroup /home/youruser/.config/n8n-mcp/env
```

Manual version:

```bash
install -d -m 700 ~/.config/n8n-mcp
cat > ~/.config/n8n-mcp/env <<'EOF'
N8N_BASE_URL=http://127.0.0.1:5678
N8N_API_KEY=REPLAC...hmod 600 ~/.config/n8n-mcp/env
```

Replace `REPLACE_ME` locally. Do not commit the real file.

## HRJ config

Add this to `~/.hrj/config.yaml`:

```yaml
mcp_servers:
  n8n:
    command: "/absolute/path/to/hrj-n8n-mcp/.venv/bin/python"
    args:
      - "/absolute/path/to/hrj-n8n-mcp/server.py"
    env:
      N8N_MCP_ENV: "/absolute/path/to/.config/n8n-mcp/env"
    timeout: 120
    connect_timeout: 30
    sampling:
      enabled: false
    tools:
      default_enabled:
        - health
        - list_workflows
        - get_workflow
        - find_workflows
        - list_executions
        - get_execution
        - recent_failures
        - export_workflow
        - container_logs
        - container_status
```

Then reload MCP in HRJ:

```text
/reload-mcp
```

Or from shell:

```bash
hrj mcp test n8n
```

## Environment variables

| Variable | Default | Description |
|----------|---------|-------------|
| `N8N_BASE_URL` | `http://127.0.0.1:5678` | n8n API base URL |
| `N8N_API_KEY` | *(required)* | n8n API key |
| `N8N_MCP_TIMEOUT` | `30` | HTTP request timeout in seconds |
| `N8N_CONTAINER_NAME` | `n8n` | Docker container name for n8n |
| `N8N_MCP_ALLOW_DOCKER_LOGS` | `true` | Enable Docker log features |
| `N8N_MCP_MAX_RETRIES` | `2` | Max retries on transient errors |
| `N8N_MCP_RETRY_DELAY` | `1.0` | Base delay between retries (seconds) |
| `N8N_MCP_ALLOW_DELETE` | `false` | Enable delete operations (requires human token) |
| `N8N_MCP_ALLOW_ACTIVATE` | `false` | Enable activate/deactivate (requires human token) |
| `N8N_MCP_LOG_DIR` | `~/.config/n8n-mcp/logs/` | Audit log directory |
| `N8N_MCP_TOKEN_DIR` | `~/.config/n8n-mcp/tokens/` | Token directory for human confirmation |
| `N8N_MCP_TOKEN_TTL` | `120` | Token time-to-live in seconds |

## Smoke test outside HRJ

```bash
. .venv/bin/activate
python -m py_compile server.py
hrj mcp test n8n
```

## Docker logs

`container_logs` shells out to Docker. If the user running HRJ cannot access Docker, set:

```text
N8N_MCP_ALLOW_DOCKER_LOGS=false
```

The rest of the API tools will still work.

## Audit logs

Write operations are logged to `~/.config/n8n-mcp/logs/audit.log`. Check this file to review:

- Which workflows were created, updated, or deleted
- When activation/deactivation occurred
- Failed attempts (blocked by env flag or missing token)
- Token validation events

## Notes for production use

- Keep n8n bound to loopback behind your reverse proxy.
- Do not expose this MCP bridge over Caddy, nginx, or Docker ports.
- Rotate n8n API keys if they ever hit chat logs, terminals, CI output, screenshots, or issue trackers.
- **Back up workflows before mutating them** (`export_workflow` before `update_workflow`).
- **Use `delete_workflow` with caution** — it is irreversible.
- **Keep write tools disabled by default** — enable only when needed.
- **Keep `N8N_MCP_ALLOW_DELETE=false`** unless actively deleting.
- **Review audit logs** periodically.

## License

MIT. See `LICENSE`.