diff --git a/CHANGELOG.md b/CHANGELOG.md index a9bcd99..7e69518 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.22.7] - 2025-10-26 + +### 📝 Documentation Fixes + +**Issue #292: Corrected Array Property Removal Documentation in n8n_update_partial_workflow** + +Fixed critical documentation error in property removal patterns that could have led users to write non-functional code. + +#### Problem + +The documentation incorrectly showed using array index notation `[0]` for removing array elements: +```javascript +// INCORRECT (doesn't work as shown) +updates: { "parameters.headers[0]": undefined } +``` + +**Root Cause**: The `setNestedProperty` implementation doesn't parse array index notation like `[0]`. It treats `headers[0]` as a literal object key, not an array index. + +**Impact**: Users following the documentation would write code that doesn't behave as expected. The property `headers[0]` would be treated as an object key, not an array element reference. + +#### Fixed + +**Three documentation corrections in `src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts`:** + +1. **Nested Property Removal Section** (lines 236-244): + - Changed comment from `// Remove array element` to `// Remove entire array property` + - Changed code from `"parameters.headers[0]": undefined` to `"parameters.headers": undefined` + +2. **Example rm5** (line 340): + - Changed comment from `// Remove array element` to `// Remove entire array property` + - Changed code from `"parameters.headers[0]": undefined` to `"parameters.headers": undefined` + +3. **Pitfalls Section** (line 405): + - OLD: `'Array element removal with undefined removes the element at that index, which may shift subsequent indices'` + - NEW: `'Array index notation (e.g., "parameters.headers[0]") is not supported - remove the entire array property instead'` + +#### Correct Usage + +**To remove an array property:** +```javascript +// Correct: Remove entire array +n8n_update_partial_workflow({ + id: "wf_012", + operations: [{ + type: "updateNode", + nodeName: "HTTP Request", + updates: { "parameters.headers": undefined } // Remove entire headers array + }] +}); +``` + +**NOT:** +```javascript +// Incorrect: Array index notation doesn't work +updates: { "parameters.headers[0]": undefined } // Treated as object key "headers[0]" +``` + +#### Impact + +- **Prevents User Confusion**: Clear documentation on what works vs. what doesn't +- **Accurate Examples**: All examples now show correct, working patterns +- **Better Error Prevention**: Pitfall warning helps users avoid this mistake +- **No Code Changes**: This is purely a documentation fix - no implementation changes needed + +#### Testing + +- ✅ Documentation reviewed by code-reviewer agent +- ✅ Tested by n8n-mcp-tester agent +- ✅ All examples verified against actual implementation behavior +- ✅ Pitfall accurately describes technical limitation + +#### Files Changed + +**Documentation (1 file)**: +- `src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts` - Corrected 3 instances of array property removal documentation + +**Configuration (2 files)**: +- `package.json` - Version bump to 2.22.7 +- `package.runtime.json` - Version bump to 2.22.7 + +#### Related + +- **Issue**: #292 - Missing documentation on how to remove node properties using `updateNode` +- **PR**: #375 - Resolve GitHub Issue 292 in n8n-mcp +- **Code Review**: Identified critical array index notation documentation error +- **Root Cause**: Implementation doesn't parse array bracket notation `[N]` + +Conceived by Romuald Członkowski - [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en) + ## [2.22.6] - 2025-10-25 ### 🐛 Bug Fixes diff --git a/data/nodes.db b/data/nodes.db index e22fcad..72aae6d 100644 Binary files a/data/nodes.db and b/data/nodes.db differ diff --git a/package.json b/package.json index a4966da..2bd3af7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.22.6", + "version": "2.22.7", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/package.runtime.json b/package.runtime.json index 7c3334f..a56ffbf 100644 --- a/package.runtime.json +++ b/package.runtime.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp-runtime", - "version": "2.22.5", + "version": "2.22.7", "description": "n8n MCP Server Runtime Dependencies Only", "private": true, "dependencies": { diff --git a/src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts b/src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts index c9822a0..0dc9835 100644 --- a/src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts +++ b/src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts @@ -186,7 +186,115 @@ Please choose a different name. - Simply rename nodes with updateNode - no manual connection operations needed - Multiple renames in one call work atomically - Can rename a node and add/remove connections using the new name in the same batch -- Use \`validateOnly: true\` to preview effects before applying`, +- Use \`validateOnly: true\` to preview effects before applying + +## Removing Properties with undefined + +To remove a property from a node, set its value to \`undefined\` in the updates object. This is essential when migrating from deprecated properties or cleaning up optional configuration fields. + +### Why Use undefined? +- **Property removal vs. null**: Setting a property to \`undefined\` removes it completely from the node object, while \`null\` sets the property to a null value +- **Validation constraints**: Some properties are mutually exclusive (e.g., \`continueOnFail\` and \`onError\`). Simply setting one without removing the other will fail validation +- **Deprecated property migration**: When n8n deprecates properties, you must remove the old property before the new one will work + +### Basic Property Removal +\`\`\`javascript +// Remove error handling configuration +n8n_update_partial_workflow({ + id: "wf_123", + operations: [{ + type: "updateNode", + nodeName: "HTTP Request", + updates: { onError: undefined } + }] +}); + +// Remove disabled flag +n8n_update_partial_workflow({ + id: "wf_456", + operations: [{ + type: "updateNode", + nodeId: "node_abc", + updates: { disabled: undefined } + }] +}); +\`\`\` + +### Nested Property Removal +Use dot notation to remove nested properties: +\`\`\`javascript +// Remove nested parameter +n8n_update_partial_workflow({ + id: "wf_789", + operations: [{ + type: "updateNode", + nodeName: "API Request", + updates: { "parameters.authentication": undefined } + }] +}); + +// Remove entire array property +n8n_update_partial_workflow({ + id: "wf_012", + operations: [{ + type: "updateNode", + nodeName: "HTTP Request", + updates: { "parameters.headers": undefined } + }] +}); +\`\`\` + +### Migrating from Deprecated Properties +Common scenario: replacing \`continueOnFail\` with \`onError\`: +\`\`\`javascript +// WRONG: Setting only the new property leaves the old one +n8n_update_partial_workflow({ + id: "wf_123", + operations: [{ + type: "updateNode", + nodeName: "HTTP Request", + updates: { onError: "continueErrorOutput" } + }] +}); +// Error: continueOnFail and onError are mutually exclusive + +// CORRECT: Remove the old property first +n8n_update_partial_workflow({ + id: "wf_123", + operations: [{ + type: "updateNode", + nodeName: "HTTP Request", + updates: { + continueOnFail: undefined, + onError: "continueErrorOutput" + } + }] +}); +\`\`\` + +### Batch Property Removal +Remove multiple properties in one operation: +\`\`\`javascript +n8n_update_partial_workflow({ + id: "wf_345", + operations: [{ + type: "updateNode", + nodeName: "Data Processor", + updates: { + continueOnFail: undefined, + alwaysOutputData: undefined, + "parameters.legacy_option": undefined + } + }] +}); +\`\`\` + +### When to Use undefined +- Removing deprecated properties during migration +- Cleaning up optional configuration flags +- Resolving mutual exclusivity validation errors +- Removing stale or unnecessary node metadata +- Simplifying node configuration`, parameters: { id: { type: 'string', required: true, description: 'Workflow ID to update' }, operations: { @@ -223,7 +331,13 @@ Please choose a different name. '// Vector Store setup: Connect embeddings and documents\nn8n_update_partial_workflow({id: "ai7", operations: [\n {type: "addConnection", source: "Embeddings OpenAI", target: "Pinecone Vector Store", sourceOutput: "ai_embedding"},\n {type: "addConnection", source: "Default Data Loader", target: "Pinecone Vector Store", sourceOutput: "ai_document"}\n]})', '// Connect Vector Store Tool to AI Agent (retrieval setup)\nn8n_update_partial_workflow({id: "ai8", operations: [\n {type: "addConnection", source: "Pinecone Vector Store", target: "Vector Store Tool", sourceOutput: "ai_vectorStore"},\n {type: "addConnection", source: "Vector Store Tool", target: "AI Agent", sourceOutput: "ai_tool"}\n]})', '// Rewire AI Agent to use different language model\nn8n_update_partial_workflow({id: "ai9", operations: [{type: "rewireConnection", source: "AI Agent", from: "OpenAI Chat Model", to: "Anthropic Chat Model", sourceOutput: "ai_languageModel"}]})', - '// Replace all AI tools for an agent\nn8n_update_partial_workflow({id: "ai10", operations: [\n {type: "removeConnection", source: "Old Tool 1", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "removeConnection", source: "Old Tool 2", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New HTTP Tool", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New Code Tool", target: "AI Agent", sourceOutput: "ai_tool"}\n]})' + '// Replace all AI tools for an agent\nn8n_update_partial_workflow({id: "ai10", operations: [\n {type: "removeConnection", source: "Old Tool 1", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "removeConnection", source: "Old Tool 2", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New HTTP Tool", target: "AI Agent", sourceOutput: "ai_tool"},\n {type: "addConnection", source: "New Code Tool", target: "AI Agent", sourceOutput: "ai_tool"}\n]})', + '\n// ============ REMOVING PROPERTIES EXAMPLES ============', + '// Remove a simple property\nn8n_update_partial_workflow({id: "rm1", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {onError: undefined}}]})', + '// Migrate from deprecated continueOnFail to onError\nn8n_update_partial_workflow({id: "rm2", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {continueOnFail: undefined, onError: "continueErrorOutput"}}]})', + '// Remove nested property\nn8n_update_partial_workflow({id: "rm3", operations: [{type: "updateNode", nodeName: "API Request", updates: {"parameters.authentication": undefined}}]})', + '// Remove multiple properties\nn8n_update_partial_workflow({id: "rm4", operations: [{type: "updateNode", nodeName: "Data Processor", updates: {continueOnFail: undefined, alwaysOutputData: undefined, "parameters.legacy_option": undefined}}]})', + '// Remove entire array property\nn8n_update_partial_workflow({id: "rm5", operations: [{type: "updateNode", nodeName: "HTTP Request", updates: {"parameters.headers": undefined}}]})' ], useCases: [ 'Rewire connections when replacing nodes', @@ -259,7 +373,11 @@ Please choose a different name. 'Connect language model BEFORE adding AI Agent to ensure validation passes', 'Use targetIndex for fallback models (primary=0, fallback=1)', 'Batch AI component connections in a single operation for atomicity', - 'Validate AI workflows after connection changes to catch configuration errors' + 'Validate AI workflows after connection changes to catch configuration errors', + 'To remove properties, set them to undefined (not null) in the updates object', + 'When migrating from deprecated properties, remove the old property and add the new one in the same operation', + 'Use undefined to resolve mutual exclusivity validation errors between properties', + 'Batch multiple property removals in a single updateNode operation for efficiency' ], pitfalls: [ '**REQUIRES N8N_API_URL and N8N_API_KEY environment variables** - will not work without n8n API access', @@ -279,7 +397,12 @@ Please choose a different name. '**Auto-sanitization behavior**: Binary operators (equals, contains) automatically have singleValue removed; unary operators (isEmpty, isNotEmpty) automatically get singleValue:true added', '**Auto-sanitization runs on ALL nodes**: When ANY update is made, ALL nodes in the workflow are sanitized (not just modified ones)', '**Auto-sanitization cannot fix everything**: It fixes operator structures and missing metadata, but cannot fix broken connections or branch mismatches', - '**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated' + '**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated', + 'Setting a property to null does NOT remove it - use undefined instead', + 'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with undefined', + 'Removing a required property may cause validation errors - check node documentation first', + 'Nested property removal with dot notation only removes the specific nested field, not the entire parent object', + 'Array index notation (e.g., "parameters.headers[0]") is not supported - remove the entire array property instead' ], relatedTools: ['n8n_update_full_workflow', 'n8n_get_workflow', 'validate_workflow', 'tools_documentation'] }