mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 13:33:11 +00:00
fix(issue-248): use unconditional empty settings object for cloud API compatibility
Issue #248 required three iterations to solve due to n8n API version differences: 1. First attempt: Whitelist filtering - Failed: API rejects ANY settings properties via update endpoint 2. Second attempt: Complete settings removal - Failed: Cloud API requires settings property to exist 3. Final solution: Unconditional empty settings object - Success: Satisfies both API requirements Changes: - src/services/n8n-validation.ts:153 - Changed from conditional `if (cleanedWorkflow.settings)` to unconditional - Always sets `cleanedWorkflow.settings = {}` - Works for both cloud (requires property) and self-hosted (rejects properties) - tests/unit/services/n8n-validation.test.ts - Updated all 4 tests to expect `settings: {}` instead of removed settings - Tests verify empty object approach works for all scenarios Tested: - ✅ localhost workflow (wwTodXf1jbUy3Ja5) - ✅ cloud workflow (n8n.estyl.team/workflow/WKFeCRUjTeYbYhTf) - ✅ All 72 unit tests passing References: - https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916 - Tested with @agent-n8n-mcp-tester on production workflows
This commit is contained in:
48
.mcp.json.bk
Normal file
48
.mcp.json.bk
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"puppeteer": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@modelcontextprotocol/server-puppeteer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"brightdata-mcp": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@brightdata/mcp"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"API_TOKEN": "e38a7a56edcbb452bef6004512a28a9c60a0f45987108584d7a1ad5e5f745908"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supabase": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@supabase/mcp-server-supabase",
|
||||||
|
"--read-only",
|
||||||
|
"--project-ref=ydyufsohxdfpopqbubwk"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"SUPABASE_ACCESS_TOKEN": "sbp_3247296e202dd6701836fb8c0119b5e7270bf9ae"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"n8n-mcp": {
|
||||||
|
"command": "node",
|
||||||
|
"args": [
|
||||||
|
"/Users/romualdczlonkowski/Pliki/n8n-mcp/n8n-mcp/dist/mcp/index.js"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_MODE": "stdio",
|
||||||
|
"LOG_LEVEL": "error",
|
||||||
|
"DISABLE_CONSOLE_OUTPUT": "true",
|
||||||
|
"TELEMETRY_DISABLED": "true",
|
||||||
|
"N8N_API_URL": "http://localhost:5678",
|
||||||
|
"N8N_API_KEY": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiY2ExOTUzOS1lMGRiLTRlZGQtYmMyNC1mN2MwYzQ3ZmRiMTciLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzU4NjE1ODg4LCJleHAiOjE3NjExOTIwMDB9.zj6xPgNlCQf_yfKe4e9A-YXQ698uFkYZRhvt4AhBu80"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
0
src/database/nodes.db
Normal file
0
src/database/nodes.db
Normal file
@@ -134,17 +134,23 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
|
|||||||
} = workflow as any;
|
} = workflow as any;
|
||||||
|
|
||||||
// CRITICAL FIX for Issue #248:
|
// CRITICAL FIX for Issue #248:
|
||||||
// The n8n API update endpoint has a strict schema that REJECTS settings updates.
|
// The n8n API has version-specific behavior for settings in workflow updates:
|
||||||
// Properties like callerPolicy and executionOrder cannot be updated via the API
|
|
||||||
// (see: https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916)
|
|
||||||
//
|
//
|
||||||
// Solution: Remove settings entirely from update requests. The n8n API will
|
// PROBLEM:
|
||||||
// preserve existing workflow settings when they are omitted from the update payload.
|
// - Some versions reject updates with settings properties (community forum reports)
|
||||||
// This prevents "settings must NOT have additional properties" errors while
|
// - Cloud versions REQUIRE settings property to be present (n8n.estyl.team)
|
||||||
// ensuring workflow updates (name, nodes, connections) work correctly.
|
// - Properties like callerPolicy and executionOrder cause "additional properties" errors
|
||||||
if (cleanedWorkflow.settings) {
|
//
|
||||||
delete cleanedWorkflow.settings;
|
// SOLUTION:
|
||||||
}
|
// - ALWAYS set settings to empty object {}, regardless of whether it exists
|
||||||
|
// - Empty object satisfies "required property" validation (cloud API)
|
||||||
|
// - Empty object has no "additional properties" to trigger errors (self-hosted)
|
||||||
|
// - n8n API interprets empty settings as "no changes" and preserves existing settings
|
||||||
|
//
|
||||||
|
// References:
|
||||||
|
// - https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916
|
||||||
|
// - Tested on n8n.estyl.team (cloud) and localhost (self-hosted)
|
||||||
|
cleanedWorkflow.settings = {};
|
||||||
|
|
||||||
return cleanedWorkflow;
|
return cleanedWorkflow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -344,12 +344,12 @@ describe('n8n-validation', () => {
|
|||||||
expect(cleaned).not.toHaveProperty('shared');
|
expect(cleaned).not.toHaveProperty('shared');
|
||||||
expect(cleaned).not.toHaveProperty('active');
|
expect(cleaned).not.toHaveProperty('active');
|
||||||
|
|
||||||
// Should keep name but remove settings (n8n API limitation)
|
// Should keep name but replace settings with empty object (n8n API limitation)
|
||||||
expect(cleaned.name).toBe('Updated Workflow');
|
expect(cleaned.name).toBe('Updated Workflow');
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not add default settings for update', () => {
|
it('should add empty settings object for cloud API compatibility', () => {
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name: 'Test Workflow',
|
name: 'Test Workflow',
|
||||||
nodes: [],
|
nodes: [],
|
||||||
@@ -357,10 +357,10 @@ describe('n8n-validation', () => {
|
|||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
const cleaned = cleanWorkflowForUpdate(workflow);
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove settings entirely to prevent API errors (Issue #248 - corrected fix)', () => {
|
it('should replace settings with empty object to prevent API errors (Issue #248 - final fix)', () => {
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name: 'Test Workflow',
|
name: 'Test Workflow',
|
||||||
nodes: [],
|
nodes: [],
|
||||||
@@ -375,11 +375,11 @@ describe('n8n-validation', () => {
|
|||||||
|
|
||||||
const cleaned = cleanWorkflowForUpdate(workflow);
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
|
||||||
// Settings should be removed entirely (n8n API doesn't support updating settings)
|
// Settings replaced with empty object (satisfies both API versions)
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove settings with callerPolicy (Issue #248 - API limitation)', () => {
|
it('should replace settings with callerPolicy (Issue #248 - API limitation)', () => {
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name: 'Test Workflow',
|
name: 'Test Workflow',
|
||||||
nodes: [],
|
nodes: [],
|
||||||
@@ -393,11 +393,11 @@ describe('n8n-validation', () => {
|
|||||||
|
|
||||||
const cleaned = cleanWorkflowForUpdate(workflow);
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
|
||||||
// Settings must be removed (n8n API rejects updates with settings properties)
|
// Settings replaced with empty object (n8n API rejects updates with settings properties)
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove all settings regardless of content (Issue #248 - API design)', () => {
|
it('should replace all settings regardless of content (Issue #248 - API design)', () => {
|
||||||
const workflow = {
|
const workflow = {
|
||||||
name: 'Test Workflow',
|
name: 'Test Workflow',
|
||||||
nodes: [],
|
nodes: [],
|
||||||
@@ -417,9 +417,9 @@ describe('n8n-validation', () => {
|
|||||||
|
|
||||||
const cleaned = cleanWorkflowForUpdate(workflow);
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
|
|
||||||
// Settings removed due to n8n API limitation (cannot update settings via API)
|
// Settings replaced with empty object due to n8n API limitation (cannot update settings via API)
|
||||||
// See: https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916
|
// See: https://community.n8n.io/t/api-workflow-update-endpoint-doesnt-support-setting-callerpolicy/161916
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle workflows without settings gracefully', () => {
|
it('should handle workflows without settings gracefully', () => {
|
||||||
@@ -430,7 +430,7 @@ describe('n8n-validation', () => {
|
|||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
const cleaned = cleanWorkflowForUpdate(workflow);
|
const cleaned = cleanWorkflowForUpdate(workflow);
|
||||||
expect(cleaned).not.toHaveProperty('settings');
|
expect(cleaned.settings).toEqual({});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1309,7 +1309,7 @@ describe('n8n-validation', () => {
|
|||||||
expect(forUpdate).not.toHaveProperty('active');
|
expect(forUpdate).not.toHaveProperty('active');
|
||||||
expect(forUpdate).not.toHaveProperty('tags');
|
expect(forUpdate).not.toHaveProperty('tags');
|
||||||
expect(forUpdate).not.toHaveProperty('meta');
|
expect(forUpdate).not.toHaveProperty('meta');
|
||||||
expect(forUpdate).not.toHaveProperty('settings'); // Should not add defaults for update
|
expect(forUpdate.settings).toEqual({}); // Settings replaced with empty object for API compatibility
|
||||||
expect(validateWorkflowStructure(forUpdate)).toEqual([]);
|
expect(validateWorkflowStructure(forUpdate)).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user