fix: add n8n 1.121 availableInMCP and callerPolicy settings support (v2.26.4) (#445)

* fix: add n8n 1.121 availableInMCP and callerPolicy settings support (v2.26.4)

n8n 1.121 introduced a new workflow setting `availableInMCP` (boolean)
that controls whether a workflow is "Available in MCP". The sanitization
whitelist was missing this field, causing it to be silently stripped
during workflow updates.

Changes:
- Added `availableInMCP` to Zod schema in workflowSettingsSchema
- Added `availableInMCP` and `callerPolicy` to safeSettingsProperties whitelist
- Both settings are now preserved during workflow updates
- Settings can be toggled via updateSettings operation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Conceived by Romuald Członkowski - www.aiadvisors.pl/en

* test: update tests for callerPolicy and availableInMCP whitelist changes

Updated 5 tests in n8n-validation.test.ts that expected callerPolicy
to be filtered out. Since callerPolicy and availableInMCP are now
whitelisted (n8n 1.121+), the tests now verify these settings are
preserved during workflow updates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Romuald Członkowski
2025-11-26 20:17:34 +01:00
committed by GitHub
parent 25784142fe
commit bac4936c6d
6 changed files with 38 additions and 21 deletions

View File

@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [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 ## [2.26.3] - 2025-11-26
### 🔧 Fixed ### 🔧 Fixed

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"name": "n8n-mcp", "name": "n8n-mcp",
"version": "2.26.3", "version": "2.26.4",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@@ -1,6 +1,6 @@
{ {
"name": "n8n-mcp-runtime", "name": "n8n-mcp-runtime",
"version": "2.26.3", "version": "2.26.4",
"description": "n8n MCP Server Runtime Dependencies Only", "description": "n8n MCP Server Runtime Dependencies Only",
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@@ -62,6 +62,7 @@ export const workflowSettingsSchema = z.object({
executionTimeout: z.number().optional(), executionTimeout: z.number().optional(),
errorWorkflow: z.string().optional(), errorWorkflow: z.string().optional(),
callerPolicy: z.enum(['any', 'workflowsFromSameOwner', 'workflowsFromAList']).optional(), callerPolicy: z.enum(['any', 'workflowsFromSameOwner', 'workflowsFromAList']).optional(),
availableInMCP: z.boolean().optional(),
}); });
// Default settings for workflow creation // Default settings for workflow creation
@@ -181,7 +182,9 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
'executionTimeout', 'executionTimeout',
'errorWorkflow', 'errorWorkflow',
'timezone', 'timezone',
'executionOrder' 'executionOrder',
'callerPolicy',
'availableInMCP',
]; ];
if (cleanedWorkflow.settings && typeof cleanedWorkflow.settings === 'object') { if (cleanedWorkflow.settings && typeof cleanedWorkflow.settings === 'object') {

View File

@@ -403,45 +403,47 @@ describe('n8n-validation', () => {
settings: { settings: {
executionOrder: 'v1' as const, executionOrder: 'v1' as const,
saveDataSuccessExecution: 'none' 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) timeSavedPerExecution: 5, // Filtered out (UI-only property)
}, },
} as any; } as any;
const cleaned = cleanWorkflowForUpdate(workflow); 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({ expect(cleaned.settings).toEqual({
executionOrder: 'v1', executionOrder: 'v1',
saveDataSuccessExecution: 'none' saveDataSuccessExecution: 'none',
callerPolicy: 'workflowsFromSameOwner'
}); });
expect(cleaned.settings).not.toHaveProperty('callerPolicy');
expect(cleaned.settings).not.toHaveProperty('timeSavedPerExecution'); 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 = { const workflow = {
name: 'Test Workflow', name: 'Test Workflow',
nodes: [], nodes: [],
connections: {}, connections: {},
settings: { settings: {
executionOrder: 'v1' as const, 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', errorWorkflow: 'N2O2nZy3aUiBRGFN',
}, },
} as any; } as any;
const cleaned = cleanWorkflowForUpdate(workflow); 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({ expect(cleaned.settings).toEqual({
executionOrder: 'v1', executionOrder: 'v1',
callerPolicy: 'workflowsFromSameOwner',
availableInMCP: true,
errorWorkflow: 'N2O2nZy3aUiBRGFN' 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 = { const workflow = {
name: 'Test Workflow', name: 'Test Workflow',
nodes: [], nodes: [],
@@ -455,14 +457,14 @@ describe('n8n-validation', () => {
saveExecutionProgress: false, saveExecutionProgress: false,
executionTimeout: 300, executionTimeout: 300,
errorWorkflow: 'error-workflow-id', 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; } as any;
const cleaned = cleanWorkflowForUpdate(workflow); const cleaned = cleanWorkflowForUpdate(workflow);
// Safe properties kept, unsafe properties filtered out // All whitelisted properties kept including callerPolicy and availableInMCP
// See: https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916
expect(cleaned.settings).toEqual({ expect(cleaned.settings).toEqual({
executionOrder: 'v0', executionOrder: 'v0',
timezone: 'UTC', timezone: 'UTC',
@@ -471,9 +473,10 @@ describe('n8n-validation', () => {
saveManualExecutions: false, saveManualExecutions: false,
saveExecutionProgress: false, saveExecutionProgress: false,
executionTimeout: 300, 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', () => { it('should handle workflows without settings gracefully', () => {
@@ -494,7 +497,6 @@ describe('n8n-validation', () => {
nodes: [], nodes: [],
connections: {}, connections: {},
settings: { settings: {
callerPolicy: 'workflowsFromSameOwner' as const, // Filtered out
timeSavedPerExecution: 5, // Filtered out (UI-only) timeSavedPerExecution: 5, // Filtered out (UI-only)
someOtherProperty: 'value', // Filtered out someOtherProperty: 'value', // Filtered out
}, },
@@ -514,19 +516,19 @@ describe('n8n-validation', () => {
connections: {}, connections: {},
settings: { settings: {
executionOrder: 'v1' as const, // Whitelisted 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 timezone: 'America/New_York', // Whitelisted
someOtherProperty: 'value', // Filtered out someOtherProperty: 'value', // Filtered out
}, },
} as any; } as any;
const cleaned = cleanWorkflowForUpdate(workflow); const cleaned = cleanWorkflowForUpdate(workflow);
// Should keep only whitelisted properties // Should keep only whitelisted properties (callerPolicy now whitelisted)
expect(cleaned.settings).toEqual({ expect(cleaned.settings).toEqual({
executionOrder: 'v1', executionOrder: 'v1',
callerPolicy: 'workflowsFromSameOwner',
timezone: 'America/New_York' timezone: 'America/New_York'
}); });
expect(cleaned.settings).not.toHaveProperty('callerPolicy');
expect(cleaned.settings).not.toHaveProperty('someOtherProperty'); expect(cleaned.settings).not.toHaveProperty('someOtherProperty');
}); });
}); });