fix: enhance node type format normalization for better AI agent compatibility (Issue #74)

- Added support for n8n-nodes-langchain.* → nodes-langchain.* normalization
- Implemented case-insensitive node name matching (e.g., chattrigger → chatTrigger)
- Added smart camelCase detection for common patterns (trigger, request, sheets, etc.)
- Fixed get_node_documentation tool to use same normalization logic as other tools
- Updated all 7 node lookup locations to use normalized types for alternatives
- Enhanced getNodeTypeAlternatives() to normalize all generated alternatives

All MCP tools now consistently handle various format variations:
- nodes-langchain.chatTrigger (correct format)
- n8n-nodes-langchain.chatTrigger (package format)
- n8n-nodes-langchain.chattrigger (package + wrong case)
- nodes-langchain.chattrigger (wrong case only)
- @n8n/n8n-nodes-langchain.chatTrigger (full npm format)

Bump version to 2.7.19

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-07-18 16:25:20 +02:00
parent a7bcd8cd1b
commit f76e2247f9
7 changed files with 124 additions and 11 deletions

View File

@@ -4,6 +4,7 @@
* Examples:
* - 'n8n-nodes-base.httpRequest' → 'nodes-base.httpRequest'
* - '@n8n/n8n-nodes-langchain.agent' → 'nodes-langchain.agent'
* - 'n8n-nodes-langchain.chatTrigger' → 'nodes-langchain.chatTrigger'
* - 'nodes-base.slack' → 'nodes-base.slack' (unchanged)
*
* @param nodeType The node type to normalize
@@ -20,6 +21,11 @@ export function normalizeNodeType(nodeType: string): string {
return nodeType.replace('@n8n/n8n-nodes-langchain.', 'nodes-langchain.');
}
// Handle n8n-nodes-langchain -> nodes-langchain (without @n8n/ prefix)
if (nodeType.startsWith('n8n-nodes-langchain.')) {
return nodeType.replace('n8n-nodes-langchain.', 'nodes-langchain.');
}
// Return unchanged if already normalized or unknown format
return nodeType;
}
@@ -36,13 +42,86 @@ export function getNodeTypeAlternatives(nodeType: string): string[] {
// Add lowercase version
alternatives.push(nodeType.toLowerCase());
// If it has a prefix, try case variations on the node name part
if (nodeType.includes('.')) {
const [prefix, nodeName] = nodeType.split('.');
// Try different case variations for the node name
if (nodeName && nodeName.toLowerCase() !== nodeName) {
alternatives.push(`${prefix}.${nodeName.toLowerCase()}`);
}
// For camelCase names like "chatTrigger", also try with capital first letter variations
// e.g., "chattrigger" -> "chatTrigger"
if (nodeName && nodeName.toLowerCase() === nodeName && nodeName.length > 1) {
// Try to detect common patterns and create camelCase version
const camelCaseVariants = generateCamelCaseVariants(nodeName);
camelCaseVariants.forEach(variant => {
alternatives.push(`${prefix}.${variant}`);
});
}
}
// If it's just a bare node name, try with common prefixes
if (!nodeType.includes('.')) {
alternatives.push(`nodes-base.${nodeType}`);
alternatives.push(`nodes-langchain.${nodeType}`);
// Also try camelCase variants for bare names
const camelCaseVariants = generateCamelCaseVariants(nodeType);
camelCaseVariants.forEach(variant => {
alternatives.push(`nodes-base.${variant}`);
alternatives.push(`nodes-langchain.${variant}`);
});
}
return alternatives;
// Normalize all alternatives and combine with originals
const normalizedAlternatives = alternatives.map(alt => normalizeNodeType(alt));
// Combine original alternatives with normalized ones and remove duplicates
return [...new Set([...alternatives, ...normalizedAlternatives])];
}
/**
* Generate camelCase variants for a lowercase string
* @param str The lowercase string
* @returns Array of possible camelCase variants
*/
function generateCamelCaseVariants(str: string): string[] {
const variants: string[] = [];
// Common patterns for n8n nodes
const patterns = [
// Pattern: wordTrigger (e.g., chatTrigger, webhookTrigger)
/^(.+)(trigger|node|request|response)$/i,
// Pattern: httpRequest, mysqlDatabase
/^(http|mysql|postgres|mongo|redis|mqtt|smtp|imap|ftp|ssh|api)(.+)$/i,
// Pattern: googleSheets, microsoftTeams
/^(google|microsoft|amazon|slack|discord|telegram)(.+)$/i,
];
for (const pattern of patterns) {
const match = str.toLowerCase().match(pattern);
if (match) {
const [, first, second] = match;
// Capitalize the second part
variants.push(first.toLowerCase() + second.charAt(0).toUpperCase() + second.slice(1).toLowerCase());
}
}
// Generic camelCase: capitalize after common word boundaries
if (variants.length === 0) {
// Try splitting on common boundaries and capitalizing
const words = str.split(/[-_\s]+/);
if (words.length > 1) {
const camelCase = words[0].toLowerCase() + words.slice(1).map(w =>
w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
).join('');
variants.push(camelCase);
}
}
return variants;
}
/**