feat: add typeVersion validation to workflow validator (v2.6.1)
- Enhanced workflow validator to enforce typeVersion on versioned nodes - Returns errors for missing typeVersion with suggested version to add - Warns about outdated typeVersion values - Prevents invalid typeVersion (zero, negative, or exceeding maximum) - Added comprehensive test script for typeVersion validation - Helps AI agents avoid common workflow creation mistakes This ensures workflows always use compatible node versions before deployment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
12
CLAUDE.md
12
CLAUDE.md
@@ -6,7 +6,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
n8n-mcp is a comprehensive documentation and knowledge server that provides AI assistants with complete access to n8n node information through the Model Context Protocol (MCP). It serves as a bridge between n8n's workflow automation platform and AI models, enabling them to understand and work with n8n nodes effectively.
|
n8n-mcp is a comprehensive documentation and knowledge server that provides AI assistants with complete access to n8n node information through the Model Context Protocol (MCP). It serves as a bridge between n8n's workflow automation platform and AI models, enabling them to understand and work with n8n nodes effectively.
|
||||||
|
|
||||||
## ✅ Latest Updates (v2.6.0)
|
## ✅ Latest Updates (v2.6.1)
|
||||||
|
|
||||||
|
### Update (v2.6.1) - Enhanced typeVersion Validation:
|
||||||
|
- ✅ **NEW: typeVersion validation** - Workflow validator now enforces typeVersion on all versioned nodes
|
||||||
|
- ✅ **Catches missing typeVersion** - Returns error with correct version to use
|
||||||
|
- ✅ **Warns on outdated versions** - Alerts when using older node versions
|
||||||
|
- ✅ **Prevents invalid versions** - Errors on versions that exceed maximum supported
|
||||||
|
- ✅ Helps AI agents avoid common workflow creation mistakes
|
||||||
|
- ✅ Ensures workflows use compatible node versions before deployment
|
||||||
|
|
||||||
### Update (v2.6.0) - n8n Management Tools Integration:
|
### Update (v2.6.0) - n8n Management Tools Integration:
|
||||||
- ✅ **NEW: 14 n8n management tools** - Create, update, execute workflows via API
|
- ✅ **NEW: 14 n8n management tools** - Create, update, execute workflows via API
|
||||||
@@ -159,6 +167,7 @@ src/
|
|||||||
│ ├── test-workflow-validation.ts # Test workflow validation (NEW in v2.5.0)
|
│ ├── test-workflow-validation.ts # Test workflow validation (NEW in v2.5.0)
|
||||||
│ ├── test-ai-workflow-validation.ts # Test AI workflow validation (NEW in v2.5.1)
|
│ ├── test-ai-workflow-validation.ts # Test AI workflow validation (NEW in v2.5.1)
|
||||||
│ ├── test-mcp-tools.ts # Test MCP tool enhancements (NEW in v2.5.1)
|
│ ├── test-mcp-tools.ts # Test MCP tool enhancements (NEW in v2.5.1)
|
||||||
|
│ ├── test-typeversion-validation.ts # Test typeVersion validation (NEW in v2.6.1)
|
||||||
│ ├── fetch-templates.ts # Fetch workflow templates from n8n.io (NEW in v2.4.1)
|
│ ├── fetch-templates.ts # Fetch workflow templates from n8n.io (NEW in v2.4.1)
|
||||||
│ └── test-templates.ts # Test template functionality (NEW in v2.4.1)
|
│ └── test-templates.ts # Test template functionality (NEW in v2.4.1)
|
||||||
├── mcp/
|
├── mcp/
|
||||||
@@ -211,6 +220,7 @@ npm run test:mcp-tools # Test MCP tool enhancements
|
|||||||
npm run test:single-session # Test single session HTTP
|
npm run test:single-session # Test single session HTTP
|
||||||
npm run test:template-validation # Test template validation
|
npm run test:template-validation # Test template validation
|
||||||
npm run test:n8n-manager # Test n8n management tools integration
|
npm run test:n8n-manager # Test n8n management tools integration
|
||||||
|
npm run test:typeversion-validation # Test typeVersion validation
|
||||||
|
|
||||||
# Workflow Validation Commands:
|
# Workflow Validation Commands:
|
||||||
npm run test:workflow-validation # Test workflow validation features
|
npm run test:workflow-validation # Test workflow validation features
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.5.1",
|
"version": "2.6.1",
|
||||||
"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",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
"test:ai-workflow-validation": "node dist/scripts/test-ai-workflow-validation.js",
|
"test:ai-workflow-validation": "node dist/scripts/test-ai-workflow-validation.js",
|
||||||
"test:mcp-tools": "node dist/scripts/test-mcp-tools.js",
|
"test:mcp-tools": "node dist/scripts/test-mcp-tools.js",
|
||||||
"test:n8n-manager": "node dist/scripts/test-n8n-manager-integration.js",
|
"test:n8n-manager": "node dist/scripts/test-n8n-manager-integration.js",
|
||||||
|
"test:typeversion-validation": "node dist/scripts/test-typeversion-validation.js",
|
||||||
"db:rebuild": "node dist/scripts/rebuild-database.js",
|
"db:rebuild": "node dist/scripts/rebuild-database.js",
|
||||||
"db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"",
|
"db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"",
|
||||||
"docs:rebuild": "ts-node src/scripts/rebuild-database.ts"
|
"docs:rebuild": "ts-node src/scripts/rebuild-database.ts"
|
||||||
|
|||||||
207
scripts/test-typeversion-validation.ts
Normal file
207
scripts/test-typeversion-validation.ts
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
#!/usr/bin/env ts-node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test script for typeVersion validation in workflow validator
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NodeRepository } from '../src/database/node-repository';
|
||||||
|
import { createDatabaseAdapter } from '../src/database/database-adapter';
|
||||||
|
import { WorkflowValidator } from '../src/services/workflow-validator';
|
||||||
|
import { EnhancedConfigValidator } from '../src/services/enhanced-config-validator';
|
||||||
|
import { Logger } from '../src/utils/logger';
|
||||||
|
|
||||||
|
const logger = new Logger({ prefix: '[test-typeversion]' });
|
||||||
|
|
||||||
|
// Test workflows with various typeVersion scenarios
|
||||||
|
const testWorkflows = {
|
||||||
|
// Workflow with missing typeVersion on versioned nodes
|
||||||
|
missingTypeVersion: {
|
||||||
|
name: 'Missing typeVersion Test',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'webhook_1',
|
||||||
|
name: 'Webhook',
|
||||||
|
type: 'n8n-nodes-base.webhook',
|
||||||
|
position: [250, 300],
|
||||||
|
parameters: {
|
||||||
|
path: '/test',
|
||||||
|
httpMethod: 'POST'
|
||||||
|
}
|
||||||
|
// Missing typeVersion - should error
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'execute_1',
|
||||||
|
name: 'Execute Command',
|
||||||
|
type: 'n8n-nodes-base.executeCommand',
|
||||||
|
position: [450, 300],
|
||||||
|
parameters: {
|
||||||
|
command: 'echo "test"'
|
||||||
|
}
|
||||||
|
// Missing typeVersion - should error
|
||||||
|
}
|
||||||
|
],
|
||||||
|
connections: {
|
||||||
|
'Webhook': {
|
||||||
|
main: [[{ node: 'Execute Command', type: 'main', index: 0 }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Workflow with outdated typeVersion
|
||||||
|
outdatedTypeVersion: {
|
||||||
|
name: 'Outdated typeVersion Test',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'http_1',
|
||||||
|
name: 'HTTP Request',
|
||||||
|
type: 'n8n-nodes-base.httpRequest',
|
||||||
|
typeVersion: 1, // Outdated - latest is likely 4+
|
||||||
|
position: [250, 300],
|
||||||
|
parameters: {
|
||||||
|
url: 'https://example.com',
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'code_1',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'n8n-nodes-base.code',
|
||||||
|
typeVersion: 1, // Outdated - latest is likely 2
|
||||||
|
position: [450, 300],
|
||||||
|
parameters: {
|
||||||
|
jsCode: 'return items;'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
connections: {
|
||||||
|
'HTTP Request': {
|
||||||
|
main: [[{ node: 'Code', type: 'main', index: 0 }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Workflow with correct typeVersion
|
||||||
|
correctTypeVersion: {
|
||||||
|
name: 'Correct typeVersion Test',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'webhook_1',
|
||||||
|
name: 'Webhook',
|
||||||
|
type: 'n8n-nodes-base.webhook',
|
||||||
|
typeVersion: 2,
|
||||||
|
position: [250, 300],
|
||||||
|
parameters: {
|
||||||
|
path: '/test',
|
||||||
|
httpMethod: 'POST'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'http_1',
|
||||||
|
name: 'HTTP Request',
|
||||||
|
type: 'n8n-nodes-base.httpRequest',
|
||||||
|
typeVersion: 4,
|
||||||
|
position: [450, 300],
|
||||||
|
parameters: {
|
||||||
|
url: 'https://example.com',
|
||||||
|
method: 'GET'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
connections: {
|
||||||
|
'Webhook': {
|
||||||
|
main: [[{ node: 'HTTP Request', type: 'main', index: 0 }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Workflow with invalid typeVersion
|
||||||
|
invalidTypeVersion: {
|
||||||
|
name: 'Invalid typeVersion Test',
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'webhook_1',
|
||||||
|
name: 'Webhook',
|
||||||
|
type: 'n8n-nodes-base.webhook',
|
||||||
|
typeVersion: 0, // Invalid - must be positive
|
||||||
|
position: [250, 300],
|
||||||
|
parameters: {
|
||||||
|
path: '/test'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'http_1',
|
||||||
|
name: 'HTTP Request',
|
||||||
|
type: 'n8n-nodes-base.httpRequest',
|
||||||
|
typeVersion: 999, // Too high - exceeds maximum
|
||||||
|
position: [450, 300],
|
||||||
|
parameters: {
|
||||||
|
url: 'https://example.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
connections: {
|
||||||
|
'Webhook': {
|
||||||
|
main: [[{ node: 'HTTP Request', type: 'main', index: 0 }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function testTypeVersionValidation() {
|
||||||
|
const dbAdapter = await createDatabaseAdapter('./data/nodes.db');
|
||||||
|
const repository = new NodeRepository(dbAdapter);
|
||||||
|
const validator = new WorkflowValidator(repository, EnhancedConfigValidator);
|
||||||
|
|
||||||
|
console.log('\n====================================');
|
||||||
|
console.log('Testing typeVersion Validation');
|
||||||
|
console.log('====================================\n');
|
||||||
|
|
||||||
|
// Check some versioned nodes to show their versions
|
||||||
|
console.log('📊 Checking versioned nodes in database:');
|
||||||
|
const versionedNodes = ['nodes-base.webhook', 'nodes-base.httpRequest', 'nodes-base.code', 'nodes-base.executeCommand'];
|
||||||
|
|
||||||
|
for (const nodeType of versionedNodes) {
|
||||||
|
const nodeInfo = repository.getNode(nodeType);
|
||||||
|
if (nodeInfo) {
|
||||||
|
console.log(`- ${nodeType}: isVersioned=${nodeInfo.isVersioned}, maxVersion=${nodeInfo.version || 'N/A'}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n');
|
||||||
|
|
||||||
|
// Test each workflow
|
||||||
|
for (const [testName, workflow] of Object.entries(testWorkflows)) {
|
||||||
|
console.log(`\n🧪 Testing: ${testName}`);
|
||||||
|
console.log('─'.repeat(50));
|
||||||
|
|
||||||
|
const result = await validator.validateWorkflow(workflow as any);
|
||||||
|
|
||||||
|
console.log(`\n✅ Valid: ${result.valid}`);
|
||||||
|
|
||||||
|
if (result.errors.length > 0) {
|
||||||
|
console.log('\n❌ Errors:');
|
||||||
|
result.errors.forEach(error => {
|
||||||
|
console.log(` - [${error.nodeName || 'Workflow'}] ${error.message}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.warnings.length > 0) {
|
||||||
|
console.log('\n⚠️ Warnings:');
|
||||||
|
result.warnings.forEach(warning => {
|
||||||
|
console.log(` - [${warning.nodeName || 'Workflow'}] ${warning.message}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.suggestions.length > 0) {
|
||||||
|
console.log('\n💡 Suggestions:');
|
||||||
|
result.suggestions.forEach(suggestion => {
|
||||||
|
console.log(` - ${suggestion}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n\n✅ typeVersion validation test completed!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the test
|
||||||
|
testTypeVersionValidation().catch(console.error);
|
||||||
@@ -259,6 +259,46 @@ export class WorkflowValidator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate typeVersion for versioned nodes
|
||||||
|
if (nodeInfo.isVersioned) {
|
||||||
|
// Check if typeVersion is missing
|
||||||
|
if (!node.typeVersion) {
|
||||||
|
result.errors.push({
|
||||||
|
type: 'error',
|
||||||
|
nodeId: node.id,
|
||||||
|
nodeName: node.name,
|
||||||
|
message: `Missing required property 'typeVersion'. Add typeVersion: ${nodeInfo.version || 1}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Check if typeVersion is invalid
|
||||||
|
else if (typeof node.typeVersion !== 'number' || node.typeVersion < 1) {
|
||||||
|
result.errors.push({
|
||||||
|
type: 'error',
|
||||||
|
nodeId: node.id,
|
||||||
|
nodeName: node.name,
|
||||||
|
message: `Invalid typeVersion: ${node.typeVersion}. Must be a positive number`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Check if typeVersion is outdated (less than latest)
|
||||||
|
else if (nodeInfo.version && node.typeVersion < nodeInfo.version) {
|
||||||
|
result.warnings.push({
|
||||||
|
type: 'warning',
|
||||||
|
nodeId: node.id,
|
||||||
|
nodeName: node.name,
|
||||||
|
message: `Outdated typeVersion: ${node.typeVersion}. Latest is ${nodeInfo.version}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Check if typeVersion exceeds maximum supported
|
||||||
|
else if (nodeInfo.version && node.typeVersion > nodeInfo.version) {
|
||||||
|
result.errors.push({
|
||||||
|
type: 'error',
|
||||||
|
nodeId: node.id,
|
||||||
|
nodeName: node.name,
|
||||||
|
message: `typeVersion ${node.typeVersion} exceeds maximum supported version ${nodeInfo.version}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate node configuration
|
// Validate node configuration
|
||||||
const nodeValidation = this.nodeValidator.validateWithMode(
|
const nodeValidation = this.nodeValidator.validateWithMode(
|
||||||
node.type,
|
node.type,
|
||||||
|
|||||||
Reference in New Issue
Block a user