diff --git a/CHANGELOG.md b/CHANGELOG.md index 97950d6..fcde21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.26.4] - 2025-11-26 + +### 🔧 Fixed + +- **n8n 1.121 Compatibility**: Added support for new workflow settings introduced in n8n 1.121 + - Added `availableInMCP` (boolean) to settings whitelist - controls "Available in MCP" toggle + - Added `callerPolicy` to settings whitelist - was already in schema but missing from sanitization + - Both settings are now preserved during workflow updates instead of being silently stripped + - Settings can be toggled via `updateSettings` operation: `{type: "updateSettings", settings: {availableInMCP: true}}` + +**Conceived by Romuald Członkowski - [AiAdvisors](https://www.aiadvisors.pl/en)** + ## [2.26.3] - 2025-11-26 ### 🔧 Fixed diff --git a/data/nodes.db b/data/nodes.db index bcf1ed8..873ca10 100644 Binary files a/data/nodes.db and b/data/nodes.db differ diff --git a/package.json b/package.json index 14e992a..c12e667 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.26.3", + "version": "2.26.4", "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 84c02f3..c8714fa 100644 --- a/package.runtime.json +++ b/package.runtime.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp-runtime", - "version": "2.26.3", + "version": "2.26.4", "description": "n8n MCP Server Runtime Dependencies Only", "private": true, "dependencies": { diff --git a/src/services/n8n-validation.ts b/src/services/n8n-validation.ts index c839fdd..3371fde 100644 --- a/src/services/n8n-validation.ts +++ b/src/services/n8n-validation.ts @@ -62,6 +62,7 @@ export const workflowSettingsSchema = z.object({ executionTimeout: z.number().optional(), errorWorkflow: z.string().optional(), callerPolicy: z.enum(['any', 'workflowsFromSameOwner', 'workflowsFromAList']).optional(), + availableInMCP: z.boolean().optional(), }); // Default settings for workflow creation @@ -181,7 +182,9 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial { 'executionTimeout', 'errorWorkflow', 'timezone', - 'executionOrder' + 'executionOrder', + 'callerPolicy', + 'availableInMCP', ]; if (cleanedWorkflow.settings && typeof cleanedWorkflow.settings === 'object') { diff --git a/tests/unit/services/n8n-validation.test.ts b/tests/unit/services/n8n-validation.test.ts index 045c26e..0211818 100644 --- a/tests/unit/services/n8n-validation.test.ts +++ b/tests/unit/services/n8n-validation.test.ts @@ -403,45 +403,47 @@ describe('n8n-validation', () => { settings: { executionOrder: 'v1' as const, saveDataSuccessExecution: 'none' as const, - callerPolicy: 'workflowsFromSameOwner' as const, // Filtered out (not in OpenAPI spec) + callerPolicy: 'workflowsFromSameOwner' as const, // Now whitelisted (n8n 1.121+) timeSavedPerExecution: 5, // Filtered out (UI-only property) }, } as any; const cleaned = cleanWorkflowForUpdate(workflow); - // Unsafe properties filtered out, safe properties kept + // Unsafe properties filtered out, safe properties kept (callerPolicy now whitelisted) expect(cleaned.settings).toEqual({ executionOrder: 'v1', - saveDataSuccessExecution: 'none' + saveDataSuccessExecution: 'none', + callerPolicy: 'workflowsFromSameOwner' }); - expect(cleaned.settings).not.toHaveProperty('callerPolicy'); expect(cleaned.settings).not.toHaveProperty('timeSavedPerExecution'); }); - it('should filter out callerPolicy (Issue #248 - API limitation)', () => { + it('should preserve callerPolicy and availableInMCP (n8n 1.121+ settings)', () => { const workflow = { name: 'Test Workflow', nodes: [], connections: {}, settings: { executionOrder: 'v1' as const, - callerPolicy: 'workflowsFromSameOwner' as const, // Filtered out + callerPolicy: 'workflowsFromSameOwner' as const, // Now whitelisted + availableInMCP: true, // New in n8n 1.121 errorWorkflow: 'N2O2nZy3aUiBRGFN', }, } as any; const cleaned = cleanWorkflowForUpdate(workflow); - // callerPolicy filtered out (causes API errors), safe properties kept + // callerPolicy and availableInMCP now whitelisted (n8n 1.121+) expect(cleaned.settings).toEqual({ executionOrder: 'v1', + callerPolicy: 'workflowsFromSameOwner', + availableInMCP: true, errorWorkflow: 'N2O2nZy3aUiBRGFN' }); - expect(cleaned.settings).not.toHaveProperty('callerPolicy'); }); - it('should filter all settings properties correctly (Issue #248 - API design)', () => { + it('should preserve all whitelisted settings properties including callerPolicy (Issue #248 - updated for n8n 1.121)', () => { const workflow = { name: 'Test Workflow', nodes: [], @@ -455,14 +457,14 @@ describe('n8n-validation', () => { saveExecutionProgress: false, executionTimeout: 300, errorWorkflow: 'error-workflow-id', - callerPolicy: 'workflowsFromAList' as const, // Filtered out (not in OpenAPI spec) + callerPolicy: 'workflowsFromAList' as const, // Now whitelisted (n8n 1.121+) + availableInMCP: false, // New in n8n 1.121 }, } as any; const cleaned = cleanWorkflowForUpdate(workflow); - // Safe properties kept, unsafe properties filtered out - // See: https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916 + // All whitelisted properties kept including callerPolicy and availableInMCP expect(cleaned.settings).toEqual({ executionOrder: 'v0', timezone: 'UTC', @@ -471,9 +473,10 @@ describe('n8n-validation', () => { saveManualExecutions: false, saveExecutionProgress: false, executionTimeout: 300, - errorWorkflow: 'error-workflow-id' + errorWorkflow: 'error-workflow-id', + callerPolicy: 'workflowsFromAList', + availableInMCP: false }); - expect(cleaned.settings).not.toHaveProperty('callerPolicy'); }); it('should handle workflows without settings gracefully', () => { @@ -494,7 +497,6 @@ describe('n8n-validation', () => { nodes: [], connections: {}, settings: { - callerPolicy: 'workflowsFromSameOwner' as const, // Filtered out timeSavedPerExecution: 5, // Filtered out (UI-only) someOtherProperty: 'value', // Filtered out }, @@ -514,19 +516,19 @@ describe('n8n-validation', () => { connections: {}, settings: { executionOrder: 'v1' as const, // Whitelisted - callerPolicy: 'workflowsFromSameOwner' as const, // Filtered out + callerPolicy: 'workflowsFromSameOwner' as const, // Now whitelisted (n8n 1.121+) timezone: 'America/New_York', // Whitelisted someOtherProperty: 'value', // Filtered out }, } as any; const cleaned = cleanWorkflowForUpdate(workflow); - // Should keep only whitelisted properties + // Should keep only whitelisted properties (callerPolicy now whitelisted) expect(cleaned.settings).toEqual({ executionOrder: 'v1', + callerPolicy: 'workflowsFromSameOwner', timezone: 'America/New_York' }); - expect(cleaned.settings).not.toHaveProperty('callerPolicy'); expect(cleaned.settings).not.toHaveProperty('someOtherProperty'); }); });