@pagelines/n8n-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,205 @@
1
+ # Node Configuration Guidelines
2
+
3
+ > Settings that make AI-created nodes human-editable.
4
+ >
5
+ > **Node types are validated.** Invalid types are blocked with suggestions before hitting n8n. Use `node_types_list` to discover available nodes.
6
+
7
+ ## Resource Locator Pattern
8
+
9
+ n8n uses `__rl` (resource locator) format for dropdown fields. Always include `cachedResultName` so humans see friendly names.
10
+
11
+ ```javascript
12
+ // Human-editable: shows "My Spreadsheet" in UI
13
+ "documentId": {
14
+ "__rl": true,
15
+ "value": "1abc123...",
16
+ "mode": "list",
17
+ "cachedResultName": "My Spreadsheet",
18
+ "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1abc123"
19
+ }
20
+
21
+ // Hard to edit: shows raw ID only
22
+ "documentId": {
23
+ "__rl": true,
24
+ "value": "1abc123...",
25
+ "mode": "id"
26
+ }
27
+ ```
28
+
29
+ | Mode | When to Use |
30
+ |------|-------------|
31
+ | `list` | Default. Shows dropdown with cached name |
32
+ | `id` | Only when ID is dynamic (from expression) |
33
+
34
+ ## Set Node
35
+
36
+ **Use JSON mode** for MCP-created nodes. Manual mapping is error-prone via API.
37
+
38
+ ```javascript
39
+ // JSON mode (reliable)
40
+ {
41
+ "mode": "raw",
42
+ "jsonOutput": "={ \"channel_id\": \"{{ $json.channelId || '123' }}\" }"
43
+ }
44
+
45
+ // Manual mapping (fragile via API)
46
+ {
47
+ "mode": "manual",
48
+ "assignments": { ... } // Complex structure, easy to break
49
+ }
50
+ ```
51
+
52
+ ## Google Sheets
53
+
54
+ Required fields (partial updates lose these):
55
+
56
+ ```javascript
57
+ {
58
+ "operation": "append",
59
+ "documentId": {
60
+ "__rl": true,
61
+ "value": "1abc...",
62
+ "mode": "list",
63
+ "cachedResultName": "Sheet Name"
64
+ },
65
+ "sheetName": {
66
+ "__rl": true,
67
+ "value": "gid=0",
68
+ "mode": "list",
69
+ "cachedResultName": "Sheet1"
70
+ },
71
+ "columns": { /* mappings */ }
72
+ }
73
+ ```
74
+
75
+ ## Gmail
76
+
77
+ Required fields:
78
+
79
+ ```javascript
80
+ {
81
+ "operation": "addLabels", // or send, get, etc.
82
+ "messageId": "={{ $('source').item.json.id }}",
83
+ "labelIds": ["Label_123", "Label_456"]
84
+ }
85
+ ```
86
+
87
+ Labels need full IDs (`Label_xxx`), not display names.
88
+
89
+ ## Discord
90
+
91
+ ```javascript
92
+ {
93
+ "authentication": "webhook",
94
+ "webhookUri": {
95
+ "__rl": true,
96
+ "value": "={{ $env.DISCORD_WEBHOOK }}",
97
+ "mode": "id"
98
+ },
99
+ "content": "Message text"
100
+ }
101
+ ```
102
+
103
+ For bot mode with guild/channel selection:
104
+
105
+ ```javascript
106
+ {
107
+ "guildId": {
108
+ "__rl": true,
109
+ "value": "123456789",
110
+ "mode": "list",
111
+ "cachedResultName": "My Server"
112
+ },
113
+ "channelId": {
114
+ "__rl": true,
115
+ "value": "987654321",
116
+ "mode": "list",
117
+ "cachedResultName": "#general"
118
+ }
119
+ }
120
+ ```
121
+
122
+ ## AI Nodes (Agent, Chain)
123
+
124
+ Always include structured output settings:
125
+
126
+ ```javascript
127
+ {
128
+ "promptType": "define",
129
+ "hasOutputParser": true,
130
+ "schemaType": "manual", // Required for nullable fields
131
+ "schema": { /* JSON Schema */ }
132
+ }
133
+ ```
134
+
135
+ Without these, AI outputs are unpredictable strings.
136
+
137
+ ## HTTP Request
138
+
139
+ Include authentication method explicitly:
140
+
141
+ ```javascript
142
+ {
143
+ "method": "POST",
144
+ "url": "https://api.example.com",
145
+ "authentication": "predefinedCredentialType",
146
+ "nodeCredentialType": "anthropicApi",
147
+ "sendBody": true,
148
+ "bodyParameters": { ... }
149
+ }
150
+ ```
151
+
152
+ ## Switch vs If
153
+
154
+ Always use Switch (not If):
155
+
156
+ ```javascript
157
+ // Switch: named outputs, extensible
158
+ {
159
+ "type": "n8n-nodes-base.switch",
160
+ "parameters": {
161
+ "rules": {
162
+ "rules": [
163
+ { "output": 0, "conditions": { ... } },
164
+ { "output": 1, "conditions": { ... } }
165
+ ]
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ If node only has true/false outputs - Switch scales better.
172
+
173
+ ## Expression Patterns
174
+
175
+ Always explicit references:
176
+
177
+ ```javascript
178
+ // Good
179
+ "={{ $('config').item.json.channel_id }}"
180
+
181
+ // Bad - breaks on node reorder
182
+ "={{ $json.channel_id }}"
183
+ ```
184
+
185
+ Environment variables for secrets:
186
+
187
+ ```javascript
188
+ "={{ $env.API_KEY }}"
189
+ ```
190
+
191
+ ## Error Handling
192
+
193
+ Set `onError` for API nodes:
194
+
195
+ ```javascript
196
+ {
197
+ "parameters": { ... },
198
+ "onError": "continueRegularOutput" // or "continueErrorOutput"
199
+ }
200
+ ```
201
+
202
+ Options:
203
+ - `stopWorkflow` - default, halts on error
204
+ - `continueRegularOutput` - ignore errors, continue
205
+ - `continueErrorOutput` - route errors to second output
package/logo.png ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagelines/n8n-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Opinionated MCP server for n8n workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,233 @@
1
+ # AI Guidelines for @pagelines/n8n-mcp
2
+
3
+ Entry point for AI assistants working on this codebase.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm run dev # Watch mode
9
+ npm run test # Run tests
10
+ npm run build # Compile TypeScript
11
+ ```
12
+
13
+ ## Codebase Map
14
+
15
+ | File | Purpose | When to modify |
16
+ |------|---------|----------------|
17
+ | `src/index.ts` | MCP server, tool dispatch | Adding new tools |
18
+ | `src/types.ts` | Type definitions | New data structures |
19
+ | `src/tools.ts` | Tool JSON schemas | New tool definitions |
20
+ | `src/n8n-client.ts` | n8n REST API calls | New API operations |
21
+ | `src/validators.ts` | Validation rules | New lint rules |
22
+ | `src/expressions.ts` | Expression parsing | Expression handling |
23
+ | `src/autofix.ts` | Auto-fix transforms | New auto-fixes |
24
+ | `src/versions.ts` | Version control | Version features |
25
+
26
+ ## Coding Standards
27
+
28
+ ### Do
29
+ - Write pure functions that return values
30
+ - Use async/await, never callbacks
31
+ - Add types for all parameters and returns
32
+ - Keep functions under 50 lines
33
+ - Name variables descriptively
34
+ - Write tests for new validators
35
+
36
+ ### Don't
37
+ - Use `any` type
38
+ - Mutate input parameters
39
+ - Add external dependencies without strong justification
40
+ - Create abstraction before duplication (rule of 3)
41
+ - Add features not explicitly requested
42
+
43
+ ## Adding a New Tool
44
+
45
+ 1. **Define type** in `types.ts` (if needed)
46
+ 2. **Add schema** in `tools.ts`:
47
+ ```typescript
48
+ {
49
+ name: 'my_tool',
50
+ description: 'What it does',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: { /* ... */ },
54
+ required: ['param1']
55
+ }
56
+ }
57
+ ```
58
+ 3. **Add handler** in `index.ts`:
59
+ ```typescript
60
+ case 'my_tool':
61
+ return await handleMyTool(args);
62
+ ```
63
+ 4. **Implement logic** in appropriate module
64
+ 5. **Add test** in `*.test.ts`
65
+
66
+ ## Adding a Validation Rule
67
+
68
+ 1. **Add rule function** in `validators.ts`:
69
+ ```typescript
70
+ function checkMyRule(workflow: N8nWorkflow): ValidationWarning[] {
71
+ const warnings: ValidationWarning[] = [];
72
+ // validation logic
73
+ if (problem) {
74
+ warnings.push({
75
+ rule: 'my_rule',
76
+ severity: 'warning', // or 'error' | 'info'
77
+ message: 'Description of issue',
78
+ nodeId: node.id,
79
+ nodeName: node.name,
80
+ suggestion: 'How to fix'
81
+ });
82
+ }
83
+ return warnings;
84
+ }
85
+ ```
86
+
87
+ 2. **Add to composition** in `validateWorkflow()`:
88
+ ```typescript
89
+ ...checkMyRule(workflow),
90
+ ```
91
+
92
+ 3. **Add test** in `validators.test.ts`:
93
+ ```typescript
94
+ it('detects my_rule violations', () => {
95
+ const workflow = createWorkflow({
96
+ // problematic config
97
+ });
98
+ const warnings = validateWorkflow(workflow);
99
+ expect(warnings).toContainEqual(
100
+ expect.objectContaining({ rule: 'my_rule' })
101
+ );
102
+ });
103
+ ```
104
+
105
+ ## Adding an Auto-Fix
106
+
107
+ 1. **Check if fixable** - some issues require human judgment
108
+ 2. **Add fix logic** in `autofix.ts`:
109
+ ```typescript
110
+ if (warning.rule === 'my_rule') {
111
+ // transform workflow
112
+ fixed.push(warning);
113
+ } else {
114
+ unfixed.push(warning);
115
+ }
116
+ ```
117
+ 3. **Update references** if renaming anything
118
+ 4. **Test both dry-run and apply modes**
119
+
120
+ ## Patterns to Follow
121
+
122
+ ### Safe Mutations
123
+ ```typescript
124
+ // Always clone before mutating
125
+ const copy = JSON.parse(JSON.stringify(original));
126
+ // Modify copy, return copy
127
+ ```
128
+
129
+ ### Async Operations
130
+ ```typescript
131
+ // All file/network operations are async
132
+ async function doThing(): Promise<Result> {
133
+ const data = await fetchData();
134
+ return transform(data);
135
+ }
136
+ ```
137
+
138
+ ### Error Responses
139
+ ```typescript
140
+ // MCP error format
141
+ return {
142
+ content: [{ type: 'text', text: 'Error message' }],
143
+ isError: true
144
+ };
145
+ ```
146
+
147
+ ### Validation Returns
148
+ ```typescript
149
+ // Always return array (empty if valid)
150
+ function validate(): ValidationWarning[] {
151
+ const warnings: ValidationWarning[] = [];
152
+ // ... checks ...
153
+ return warnings;
154
+ }
155
+ ```
156
+
157
+ ## Testing Patterns
158
+
159
+ ### Fixture Factory
160
+ ```typescript
161
+ function createWorkflow(overrides: Partial<N8nWorkflow> = {}): N8nWorkflow {
162
+ return {
163
+ id: 'test-id',
164
+ name: 'test_workflow',
165
+ nodes: [],
166
+ connections: {},
167
+ ...overrides
168
+ };
169
+ }
170
+ ```
171
+
172
+ ### Assertion Patterns
173
+ ```typescript
174
+ // Check warning exists
175
+ expect(warnings).toContainEqual(
176
+ expect.objectContaining({ rule: 'rule_name' })
177
+ );
178
+
179
+ // Check no warnings
180
+ expect(warnings).toHaveLength(0);
181
+
182
+ // Check severity
183
+ expect(warnings[0].severity).toBe('error');
184
+ ```
185
+
186
+ ## Out of Scope
187
+
188
+ Do not implement:
189
+ - Node documentation/search (use web search)
190
+ - Template marketplace features
191
+ - Credential management
192
+ - Multi-instance sync
193
+ - Real-time execution monitoring
194
+
195
+ These are either security risks or solved problems (Google, n8n UI).
196
+
197
+ ## Questions to Ask
198
+
199
+ Before adding a feature:
200
+ 1. Does this serve workflow editing/validation/versioning?
201
+ 2. Can this be solved with existing web search?
202
+ 3. Does this add runtime dependencies?
203
+ 4. Is there duplication that justifies abstraction?
204
+
205
+ If any answer suggests bloat, reconsider.
206
+
207
+ ## File Locations
208
+
209
+ ```
210
+ ~/.n8n-mcp/versions/ # Version control storage
211
+ {workflowId}/
212
+ {timestamp}_{hash}.json
213
+ ```
214
+
215
+ ## Environment Variables
216
+
217
+ ```bash
218
+ N8N_API_URL=http://localhost:5678 # n8n instance URL
219
+ N8N_API_KEY=your-api-key # n8n API key
220
+ ```
221
+
222
+ ## Debugging
223
+
224
+ ```bash
225
+ # Run with verbose output
226
+ DEBUG=* npm run dev
227
+
228
+ # Test single file
229
+ npx vitest run src/validators.test.ts
230
+
231
+ # Watch single test
232
+ npx vitest watch src/validators.test.ts
233
+ ```
@@ -0,0 +1,220 @@
1
+ # Architecture
2
+
3
+ **Opinionated** n8n workflow automation. Enforces conventions, blocks mistakes, auto-fixes issues.
4
+
5
+ ## vs czlonkowski/n8n-mcp
6
+
7
+ | Concern | czlonkowski | @pagelines |
8
+ |---------|-------------|------------|
9
+ | Philosophy | Permissive | Opinionated |
10
+ | Node docs | 70MB SQLite, 1084 nodes | None (use Google) |
11
+ | Templates | 2,709 indexed | None (use n8n.io) |
12
+ | Update mode | Full replace | Patch (preserves params) |
13
+ | After mutations | Nothing | Auto-validate, auto-fix, format |
14
+ | Invalid node types | API error | Blocked with suggestions |
15
+ | Version control | Limited | Auto-snapshot, diff, rollback |
16
+ | Validation | Basic | Rules + expressions + circular refs |
17
+ | Auto-fix | No | Yes (automatic) |
18
+ | Dependencies | SQLite, heavy | Zero runtime |
19
+ | Lines of code | ~10k+ | ~1,500 |
20
+
21
+ ## Modules
22
+
23
+ ```
24
+ src/
25
+ ├── index.ts # MCP server, tool dispatch
26
+ ├── types.ts # Type definitions
27
+ ├── tools.ts # Tool schemas (JSON Schema)
28
+ ├── n8n-client.ts # n8n REST API client
29
+ ├── validators.ts # Validation rules + node type validation
30
+ ├── expressions.ts # Expression parsing ({{ }})
31
+ ├── autofix.ts # Auto-fix transforms
32
+ ├── versions.ts # Version control (local fs)
33
+ └── response-format.ts # Token-efficient response formatting
34
+ ```
35
+
36
+ ## Data Flow
37
+
38
+ ```
39
+ Claude Request
40
+
41
+ MCP Server (stdio)
42
+
43
+ Tool Handler
44
+
45
+ ┌─────────────────────────────────┐
46
+ │ n8n-client validators │
47
+ │ expressions autofix │
48
+ │ versions response-format │
49
+ └─────────────────────────────────┘
50
+
51
+ JSON Response → Claude
52
+ ```
53
+
54
+ ## Auto-Cleanup Pipeline
55
+
56
+ Every `workflow_create` and `workflow_update` runs this automatically:
57
+
58
+ ```
59
+ 1. Validate node types → Block if invalid (with suggestions)
60
+ 2. Execute operation
61
+ 3. Validate workflow → Get warnings
62
+ 4. Auto-fix fixable issues → snake_case, $json refs, AI settings
63
+ 5. Format workflow → Sort nodes, remove nulls
64
+ 6. Update if changes → Apply cleanup to n8n
65
+ 7. Return result → Only unfixable warnings shown
66
+ ```
67
+
68
+ ## Tools (20 total)
69
+
70
+ ### Workflow (8)
71
+ | Tool | Description |
72
+ |------|-------------|
73
+ | `workflow_list` | List workflows, filter by active |
74
+ | `workflow_get` | Get full workflow |
75
+ | `workflow_create` | Create with nodes/connections (auto-validates, auto-fixes) |
76
+ | `workflow_update` | Patch operations (auto-validates, auto-fixes) |
77
+ | `workflow_delete` | Delete workflow |
78
+ | `workflow_activate` | Enable triggers |
79
+ | `workflow_deactivate` | Disable triggers |
80
+ | `workflow_execute` | Trigger via webhook |
81
+
82
+ ### Execution (2)
83
+ | Tool | Description |
84
+ |------|-------------|
85
+ | `execution_list` | List executions, filter by status |
86
+ | `execution_get` | Get execution with run data |
87
+
88
+ ### Validation (3)
89
+ | Tool | Description |
90
+ |------|-------------|
91
+ | `workflow_validate` | Check rules + expressions + circular refs |
92
+ | `workflow_autofix` | Fix auto-fixable issues (dry-run default) |
93
+ | `workflow_format` | Sort nodes, clean nulls |
94
+
95
+ ### Discovery (1)
96
+ | Tool | Description |
97
+ |------|-------------|
98
+ | `node_types_list` | Search available node types by name/category |
99
+
100
+ ### Version Control (6)
101
+ | Tool | Description |
102
+ |------|-------------|
103
+ | `version_list` | List snapshots for workflow |
104
+ | `version_get` | Get specific version |
105
+ | `version_save` | Manual snapshot with reason |
106
+ | `version_rollback` | Restore previous (auto-saves current first) |
107
+ | `version_diff` | Compare versions |
108
+ | `version_stats` | Version control statistics |
109
+
110
+ ## Patch Operations
111
+
112
+ `workflow_update` accepts these operation types:
113
+
114
+ ```
115
+ addNode, removeNode, updateNode
116
+ addConnection, removeConnection
117
+ updateSettings, updateName
118
+ ```
119
+
120
+ Key: Preserves unmodified parameters.
121
+
122
+ ## Node Type Validation
123
+
124
+ Before `workflow_create` or `workflow_update` with `addNode`:
125
+
126
+ 1. Fetch available types from n8n API
127
+ 2. Validate all node types exist
128
+ 3. **Block** if invalid with suggestions (fuzzy matching)
129
+
130
+ ```
131
+ Error: Invalid node types detected:
132
+ Invalid node type "n8n-nodes-base.webhok" for node "trigger".
133
+ Did you mean: n8n-nodes-base.webhook?
134
+
135
+ Use node_types_list to discover available node types.
136
+ ```
137
+
138
+ ## Validation Rules
139
+
140
+ All rules are checked automatically on every `workflow_create` and `workflow_update`:
141
+
142
+ | Rule | Severity | Auto-fix | Description |
143
+ |------|----------|----------|-------------|
144
+ | `snake_case` | warning | Yes | Names should be snake_case |
145
+ | `explicit_reference` | warning | Yes | Use `$('node')` not `$json` |
146
+ | `ai_structured_output` | warning | Yes | AI node missing structured output |
147
+ | `no_hardcoded_ids` | info | No | Avoid hardcoded IDs |
148
+ | `no_hardcoded_secrets` | info | No | Consider using $env vars |
149
+ | `code_node_usage` | info | No | Code node detected |
150
+ | `in_memory_storage` | warning | No | Non-persistent storage |
151
+ | `orphan_node` | warning | No | Node has no connections |
152
+ | `node_exists` | error | No | Node doesn't exist (for updates) |
153
+ | `parameter_preservation` | error | No | Update would lose parameters |
154
+
155
+ ## Expression Validation
156
+
157
+ | Issue | Severity | Pattern |
158
+ |-------|----------|---------|
159
+ | Uses `$json` | warning | `$json.` without `$('` prefix |
160
+ | Uses `$input` | info | `$input.` usage |
161
+ | Missing node reference | error | `$('node')` where node doesn't exist |
162
+ | Unclosed `}}` | error | Unmatched delimiters |
163
+ | Unbalanced parens/brackets | error | `(` vs `)`, `[` vs `]` |
164
+ | Deprecated `$node` | warning | `$node.` pattern |
165
+ | Deep property without `?.` | info | Missing optional chaining |
166
+
167
+ Plus: **Circular reference detection** across all expressions.
168
+
169
+ ## Auto-Fix
170
+
171
+ | Rule | Transform |
172
+ |------|-----------|
173
+ | `snake_case` | Rename + update all references |
174
+ | `explicit_reference` | `$json.x` → `$('prev_node').item.json.x` |
175
+ | `ai_structured_output` | Add `promptType: "define"`, `hasOutputParser: true` |
176
+
177
+ **Not fixable** (require judgment): secrets, hardcoded IDs, orphan nodes, code nodes, memory storage.
178
+
179
+ ## Version Control
180
+
181
+ Storage: `~/.n8n-mcp/versions/{workflowId}/{timestamp}_{hash}.json`
182
+
183
+ ```json
184
+ {
185
+ "id": "1704067200000_abc123",
186
+ "workflowId": "123",
187
+ "timestamp": "2024-01-01T00:00:00.000Z",
188
+ "reason": "before update",
189
+ "metadata": {
190
+ "name": "my_workflow",
191
+ "nodeCount": 5,
192
+ "contentHash": "abc123"
193
+ },
194
+ "workflow": { /* full snapshot */ }
195
+ }
196
+ ```
197
+
198
+ Features:
199
+ - Hash-based deduplication (no duplicate saves)
200
+ - Max versions pruning (default: 20)
201
+ - Auto-save before `workflow_update` and `version_rollback`
202
+
203
+ ## Extension
204
+
205
+ Add validation rule:
206
+ ```typescript
207
+ // validators.ts
208
+ function checkMyRule(workflow: N8nWorkflow): ValidationWarning[] {
209
+ // return warnings
210
+ }
211
+ // Add to validateWorkflow()
212
+ ```
213
+
214
+ Add auto-fix:
215
+ ```typescript
216
+ // autofix.ts
217
+ if (warning.rule === 'my_rule' && fixable) {
218
+ // transform workflow
219
+ }
220
+ ```