mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-07 05:53:07 +00:00
fix: correct version extraction and typeVersion validation for langchain nodes
This commit fixes two critical bugs affecting AI Agent and other langchain nodes: 1. Version Extraction Bug (node-parser.ts) - AI Agent was returning version "3" instead of "2.2" (the defaultVersion) - Root cause: extractVersion() checked non-existent instance.baseDescription.defaultVersion - Fix: Updated priority to check currentVersion first, then description.defaultVersion - Impact: All VersionedNodeType nodes now return correct version 2. typeVersion Validation Bypass (workflow-validator.ts) - Langchain nodes with invalid typeVersion passed validation (even typeVersion: 99999) - Root cause: langchain skip happened before typeVersion validation - Fix: Moved typeVersion validation before langchain parameter skip - Impact: Invalid typeVersion values now properly caught for all nodes Also includes: - Database rebuilt with corrected version data (536 nodes) - Version bump: 2.17.3 → 2.17.4 - Comprehensive CHANGELOG entry 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
89
CHANGELOG.md
89
CHANGELOG.md
@@ -5,6 +5,95 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.17.4] - 2025-10-07
|
||||
|
||||
### 🔧 Validation
|
||||
|
||||
**Fixed critical version extraction and typeVersion validation bugs.**
|
||||
|
||||
This release fixes two critical bugs that caused incorrect version data and validation bypasses for langchain nodes.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- **Version Extraction Bug (CRITICAL)**
|
||||
- **Issue:** AI Agent node returned version "3" instead of "2.2" (the defaultVersion)
|
||||
- **Impact:**
|
||||
- MCP tools (`get_node_essentials`, `get_node_info`) returned incorrect version "3"
|
||||
- Version "3" exists but n8n explicitly marks it as unstable ("Keep 2.2 until blocking bugs are fixed")
|
||||
- AI agents created workflows with wrong typeVersion, causing runtime issues
|
||||
- **Root Cause:** `extractVersion()` in node-parser.ts checked `instance.baseDescription.defaultVersion` which doesn't exist on VersionedNodeType instances
|
||||
- **Fix:** Updated version extraction priority in `node-parser.ts:137-200`
|
||||
1. Priority 1: Check `currentVersion` property (what VersionedNodeType actually uses)
|
||||
2. Priority 2: Check `description.defaultVersion` (fixed property name from `baseDescription`)
|
||||
3. Priority 3: Fallback to max(nodeVersions) as last resort
|
||||
- **Verification:** AI Agent node now correctly returns version "2.2" across all MCP tools
|
||||
|
||||
- **typeVersion Validation Bypass (CRITICAL)**
|
||||
- **Issue:** Langchain nodes with invalid typeVersion passed validation (even `typeVersion: 99999`)
|
||||
- **Impact:**
|
||||
- Invalid typeVersion values were never caught during validation
|
||||
- Workflows with non-existent typeVersions passed validation but failed at runtime in n8n
|
||||
- Validation was completely bypassed for all langchain nodes (AI Agent, Chat Trigger, OpenAI Chat Model, etc.)
|
||||
- **Root Cause:** `workflow-validator.ts:400-405` skipped ALL validation for langchain nodes before typeVersion check
|
||||
- **Fix:** Moved typeVersion validation BEFORE langchain skip in `workflow-validator.ts:447-493`
|
||||
- typeVersion now validated for ALL nodes including langchain
|
||||
- Validation runs before parameter validation skip
|
||||
- Checks for missing, invalid, outdated, and exceeding-maximum typeVersion values
|
||||
- **Verification:** Workflows with invalid typeVersion now correctly fail validation
|
||||
|
||||
#### Technical Details
|
||||
|
||||
**Version Extraction Fix:**
|
||||
```typescript
|
||||
// BEFORE (BROKEN):
|
||||
if (instance?.baseDescription?.defaultVersion) { // Property doesn't exist!
|
||||
return instance.baseDescription.defaultVersion.toString();
|
||||
}
|
||||
|
||||
// AFTER (FIXED):
|
||||
if (instance?.currentVersion !== undefined) { // What VersionedNodeType actually uses
|
||||
return instance.currentVersion.toString();
|
||||
}
|
||||
if (instance?.description?.defaultVersion) { // Correct property name
|
||||
return instance.description.defaultVersion.toString();
|
||||
}
|
||||
```
|
||||
|
||||
**typeVersion Validation Fix:**
|
||||
```typescript
|
||||
// BEFORE (BROKEN):
|
||||
// Skip ALL node repository validation for langchain nodes
|
||||
if (normalizedType.startsWith('nodes-langchain.')) {
|
||||
continue; // typeVersion validation never runs!
|
||||
}
|
||||
|
||||
// AFTER (FIXED):
|
||||
// Validate typeVersion for ALL versioned nodes (including langchain)
|
||||
if (nodeInfo.isVersioned) {
|
||||
// ... typeVersion validation ...
|
||||
}
|
||||
|
||||
// THEN skip parameter validation for langchain nodes
|
||||
if (normalizedType.startsWith('nodes-langchain.')) {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
#### Impact
|
||||
|
||||
- **Version Accuracy:** AI Agent and all VersionedNodeType nodes now return correct version (2.2, not 3)
|
||||
- **Validation Reliability:** Invalid typeVersion values are now caught for langchain nodes
|
||||
- **Workflow Stability:** Prevents creation of workflows with non-existent typeVersions
|
||||
- **Database Rebuilt:** 536 nodes reloaded with corrected version data
|
||||
|
||||
#### Testing
|
||||
|
||||
- **Unit Tests:** All existing tests passing
|
||||
- **Integration Tests:** Verified with n8n-mcp-tester agent
|
||||
- Version consistency between `get_node_essentials` and `get_node_info` ✅
|
||||
- typeVersion validation catches invalid values (99, 100000) ✅
|
||||
- AI Agent correctly reports version "2.2" ✅
|
||||
|
||||
## [2.17.3] - 2025-10-07
|
||||
|
||||
### 🔧 Validation
|
||||
|
||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "n8n-mcp",
|
||||
"version": "2.17.3",
|
||||
"version": "2.17.4",
|
||||
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
|
||||
@@ -135,16 +135,23 @@ export class NodeParser {
|
||||
}
|
||||
|
||||
private extractVersion(nodeClass: any): string {
|
||||
// Check instance for baseDescription first
|
||||
// Check instance properties first
|
||||
try {
|
||||
const instance = typeof nodeClass === 'function' ? new nodeClass() : nodeClass;
|
||||
|
||||
// Handle instance-level baseDescription
|
||||
if (instance?.baseDescription?.defaultVersion) {
|
||||
return instance.baseDescription.defaultVersion.toString();
|
||||
// PRIORITY 1: Check currentVersion (what VersionedNodeType actually uses)
|
||||
// For VersionedNodeType, currentVersion = defaultVersion ?? max(nodeVersions)
|
||||
if (instance?.currentVersion !== undefined) {
|
||||
return instance.currentVersion.toString();
|
||||
}
|
||||
|
||||
// Handle instance-level nodeVersions
|
||||
// PRIORITY 2: Handle instance-level description.defaultVersion
|
||||
// VersionedNodeType stores baseDescription as 'description', not 'baseDescription'
|
||||
if (instance?.description?.defaultVersion) {
|
||||
return instance.description.defaultVersion.toString();
|
||||
}
|
||||
|
||||
// PRIORITY 3: Handle instance-level nodeVersions (fallback to max)
|
||||
if (instance?.nodeVersions) {
|
||||
const versions = Object.keys(instance.nodeVersions);
|
||||
return Math.max(...versions.map(Number)).toString();
|
||||
@@ -154,7 +161,6 @@ export class NodeParser {
|
||||
if (instance?.description?.version) {
|
||||
const version = instance.description.version;
|
||||
if (Array.isArray(version)) {
|
||||
// Find the maximum version from the array
|
||||
const maxVersion = Math.max(...version.map((v: any) => parseFloat(v.toString())));
|
||||
return maxVersion.toString();
|
||||
} else if (typeof version === 'number' || typeof version === 'string') {
|
||||
@@ -167,8 +173,9 @@ export class NodeParser {
|
||||
}
|
||||
|
||||
// Handle class-level VersionedNodeType with defaultVersion
|
||||
if (nodeClass.baseDescription?.defaultVersion) {
|
||||
return nodeClass.baseDescription.defaultVersion.toString();
|
||||
// Note: Most VersionedNodeType classes don't have static properties
|
||||
if (nodeClass.description?.defaultVersion) {
|
||||
return nodeClass.description.defaultVersion.toString();
|
||||
}
|
||||
|
||||
// Handle class-level VersionedNodeType with nodeVersions
|
||||
|
||||
@@ -397,14 +397,7 @@ export class WorkflowValidator {
|
||||
node.type = normalizedType;
|
||||
}
|
||||
|
||||
// Skip ALL node repository validation for langchain nodes
|
||||
// They have dedicated AI-specific validators in validateAISpecificNodes()
|
||||
// This prevents parameter validation conflicts and ensures proper AI validation
|
||||
if (normalizedType.startsWith('nodes-langchain.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get node definition using normalized type
|
||||
// Get node definition using normalized type (needed for typeVersion validation)
|
||||
const nodeInfo = this.nodeRepository.getNode(normalizedType);
|
||||
|
||||
if (!nodeInfo) {
|
||||
@@ -451,7 +444,8 @@ export class WorkflowValidator {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate typeVersion for versioned nodes
|
||||
// Validate typeVersion for ALL versioned nodes (including langchain nodes)
|
||||
// This validation runs BEFORE the langchain skip to ensure typeVersion is checked
|
||||
if (nodeInfo.isVersioned) {
|
||||
// Check if typeVersion is missing
|
||||
if (!node.typeVersion) {
|
||||
@@ -491,6 +485,13 @@ export class WorkflowValidator {
|
||||
}
|
||||
}
|
||||
|
||||
// Skip parameter validation for langchain nodes
|
||||
// They have dedicated AI-specific validators in validateAISpecificNodes()
|
||||
// This prevents parameter validation conflicts and ensures proper AI validation
|
||||
if (normalizedType.startsWith('nodes-langchain.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate node configuration
|
||||
const nodeValidation = this.nodeValidator.validateWithMode(
|
||||
node.type,
|
||||
|
||||
Reference in New Issue
Block a user