fix: normalize node type prefixes for n8n workflow exports (#71)
- Add centralized normalizeNodeType utility to handle prefix conversion - n8n-nodes-base.* → nodes-base.* - @n8n/n8n-nodes-langchain.* → nodes-langchain.* - Update all 9 affected MCP tools to use normalized node types - AI agents can now use node types directly from n8n workflow exports - Maintains backward compatibility with existing shortened prefixes - Add comprehensive test coverage for all affected methods Fixes #71 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
@@ -5,6 +5,25 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2.7.18] - 2025-07-18
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Node type prefix normalization for AI agents** (Issue #71)
|
||||||
|
- AI agents can now use node types directly from n8n workflow exports without manual conversion
|
||||||
|
- Added automatic normalization: `n8n-nodes-base.httpRequest` → `nodes-base.httpRequest`
|
||||||
|
- Added automatic normalization: `@n8n/n8n-nodes-langchain.agent` → `nodes-langchain.agent`
|
||||||
|
- Fixed 9 MCP tools that were failing with full package names:
|
||||||
|
- `get_node_info`, `get_node_essentials`, `get_node_as_tool_info`
|
||||||
|
- `search_node_properties`, `validate_node_minimal`, `validate_node_config`
|
||||||
|
- `get_property_dependencies`, `search_nodes`, `get_node_documentation`
|
||||||
|
- Maintains backward compatibility - existing short prefixes continue to work
|
||||||
|
- Created centralized `normalizeNodeType` utility for consistent handling across all tools
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Node type utilities** in `src/utils/node-utils.ts`
|
||||||
|
- `normalizeNodeType()` - Converts full package names to database format
|
||||||
|
- `getNodeTypeAlternatives()` - Provides fallback options for edge cases
|
||||||
|
|
||||||
## [2.7.17] - 2025-07-17
|
## [2.7.17] - 2025-07-17
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
@@ -664,6 +683,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Basic n8n and MCP integration
|
- Basic n8n and MCP integration
|
||||||
- Core workflow automation features
|
- Core workflow automation features
|
||||||
|
|
||||||
|
[2.7.18]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.17...v2.7.18
|
||||||
[2.7.17]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.16...v2.7.17
|
[2.7.17]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.16...v2.7.17
|
||||||
[2.7.16]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.15...v2.7.16
|
[2.7.16]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.15...v2.7.16
|
||||||
[2.7.15]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.13...v2.7.15
|
[2.7.15]: https://github.com/czlonkowski/n8n-mcp/compare/v2.7.13...v2.7.15
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.7.17",
|
"version": "2.7.18",
|
||||||
"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",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp-runtime",
|
"name": "n8n-mcp-runtime",
|
||||||
"version": "2.7.13",
|
"version": "2.7.18",
|
||||||
"description": "n8n MCP Server Runtime Dependencies Only",
|
"description": "n8n MCP Server Runtime Dependencies Only",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import * as n8nHandlers from './handlers-n8n-manager';
|
|||||||
import { handleUpdatePartialWorkflow } from './handlers-workflow-diff';
|
import { handleUpdatePartialWorkflow } from './handlers-workflow-diff';
|
||||||
import { getToolDocumentation, getToolsOverview } from './tools-documentation';
|
import { getToolDocumentation, getToolsOverview } from './tools-documentation';
|
||||||
import { PROJECT_VERSION } from '../utils/version';
|
import { PROJECT_VERSION } from '../utils/version';
|
||||||
|
import { normalizeNodeType, getNodeTypeAlternatives } from '../utils/node-utils';
|
||||||
|
|
||||||
interface NodeRow {
|
interface NodeRow {
|
||||||
node_type: string;
|
node_type: string;
|
||||||
@@ -341,16 +342,19 @@ export class N8NDocumentationMCPServer {
|
|||||||
private async getNodeInfo(nodeType: string): Promise<any> {
|
private async getNodeInfo(nodeType: string): Promise<any> {
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
let node = this.repository.getNode(nodeType);
|
|
||||||
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -359,10 +363,10 @@ export class N8NDocumentationMCPServer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add AI tool capabilities information
|
// Add AI tool capabilities information
|
||||||
@@ -394,6 +398,16 @@ export class N8NDocumentationMCPServer {
|
|||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
|
|
||||||
|
// Normalize the query if it looks like a full node type
|
||||||
|
let normalizedQuery = query;
|
||||||
|
|
||||||
|
// Check if query contains node type patterns and normalize them
|
||||||
|
if (query.includes('n8n-nodes-base.') || query.includes('@n8n/n8n-nodes-langchain.')) {
|
||||||
|
normalizedQuery = query
|
||||||
|
.replace(/n8n-nodes-base\./g, 'nodes-base.')
|
||||||
|
.replace(/@n8n\/n8n-nodes-langchain\./g, 'nodes-langchain.');
|
||||||
|
}
|
||||||
|
|
||||||
const searchMode = options?.mode || 'OR';
|
const searchMode = options?.mode || 'OR';
|
||||||
|
|
||||||
// Check if FTS5 table exists
|
// Check if FTS5 table exists
|
||||||
@@ -403,11 +417,11 @@ export class N8NDocumentationMCPServer {
|
|||||||
`).get();
|
`).get();
|
||||||
|
|
||||||
if (ftsExists) {
|
if (ftsExists) {
|
||||||
// Use FTS5 search
|
// Use FTS5 search with normalized query
|
||||||
return this.searchNodesFTS(query, limit, searchMode);
|
return this.searchNodesFTS(normalizedQuery, limit, searchMode);
|
||||||
} else {
|
} else {
|
||||||
// Fallback to LIKE search (existing implementation)
|
// Fallback to LIKE search with normalized query
|
||||||
return this.searchNodesLIKE(query, limit);
|
return this.searchNodesLIKE(normalizedQuery, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,11 +952,23 @@ export class N8NDocumentationMCPServer {
|
|||||||
private async getNodeDocumentation(nodeType: string): Promise<any> {
|
private async getNodeDocumentation(nodeType: string): Promise<any> {
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
if (!this.db) throw new Error('Database not initialized');
|
if (!this.db) throw new Error('Database not initialized');
|
||||||
const node = this.db!.prepare(`
|
|
||||||
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.db!.prepare(`
|
||||||
SELECT node_type, display_name, documentation, description
|
SELECT node_type, display_name, documentation, description
|
||||||
FROM nodes
|
FROM nodes
|
||||||
WHERE node_type = ?
|
WHERE node_type = ?
|
||||||
`).get(nodeType) as NodeRow | undefined;
|
`).get(normalizedType) as NodeRow | undefined;
|
||||||
|
|
||||||
|
// If not found and normalization changed the type, try original
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
node = this.db!.prepare(`
|
||||||
|
SELECT node_type, display_name, documentation, description
|
||||||
|
FROM nodes
|
||||||
|
WHERE node_type = ?
|
||||||
|
`).get(nodeType) as NodeRow | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
@@ -1030,16 +1056,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
// Get the full node information
|
// Get the full node information
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1048,10 +1076,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get properties (already parsed by repository)
|
// Get properties (already parsed by repository)
|
||||||
@@ -1101,16 +1129,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
|
|
||||||
// Get the node
|
// Get the node
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1119,10 +1149,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get properties and search (already parsed by repository)
|
// Get properties and search (already parsed by repository)
|
||||||
@@ -1257,16 +1287,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
|
|
||||||
// Get node info to access properties
|
// Get node info to access properties
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1275,10 +1307,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get properties
|
// Get properties
|
||||||
@@ -1312,16 +1344,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
|
|
||||||
// Get node info to access properties
|
// Get node info to access properties
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1330,10 +1364,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get properties
|
// Get properties
|
||||||
@@ -1364,16 +1398,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
|
|
||||||
// Get node info
|
// Get node info
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1382,10 +1418,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine common AI tool use cases based on node type
|
// Determine common AI tool use cases based on node type
|
||||||
@@ -1538,16 +1574,18 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
if (!this.repository) throw new Error('Repository not initialized');
|
if (!this.repository) throw new Error('Repository not initialized');
|
||||||
|
|
||||||
// Get node info
|
// Get node info
|
||||||
let node = this.repository.getNode(nodeType);
|
// First try with normalized type
|
||||||
|
const normalizedType = normalizeNodeType(nodeType);
|
||||||
|
let node = this.repository.getNode(normalizedType);
|
||||||
|
|
||||||
|
if (!node && normalizedType !== nodeType) {
|
||||||
|
// Try original if normalization changed it
|
||||||
|
node = this.repository.getNode(nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
// Try alternative formats
|
// Fallback to other alternatives for edge cases
|
||||||
const alternatives = [
|
const alternatives = getNodeTypeAlternatives(nodeType);
|
||||||
nodeType,
|
|
||||||
nodeType.replace('n8n-nodes-base.', ''),
|
|
||||||
`n8n-nodes-base.${nodeType}`,
|
|
||||||
nodeType.toLowerCase()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const alt of alternatives) {
|
for (const alt of alternatives) {
|
||||||
const found = this.repository!.getNode(alt);
|
const found = this.repository!.getNode(alt);
|
||||||
@@ -1556,10 +1594,10 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!node) {
|
|
||||||
throw new Error(`Node ${nodeType} not found`);
|
if (!node) {
|
||||||
}
|
throw new Error(`Node ${nodeType} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get properties
|
// Get properties
|
||||||
|
|||||||
46
src/utils/node-utils.ts
Normal file
46
src/utils/node-utils.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Normalizes node type from n8n export format to database format
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* - 'n8n-nodes-base.httpRequest' → 'nodes-base.httpRequest'
|
||||||
|
* - '@n8n/n8n-nodes-langchain.agent' → 'nodes-langchain.agent'
|
||||||
|
* - 'nodes-base.slack' → 'nodes-base.slack' (unchanged)
|
||||||
|
*
|
||||||
|
* @param nodeType The node type to normalize
|
||||||
|
* @returns The normalized node type
|
||||||
|
*/
|
||||||
|
export function normalizeNodeType(nodeType: string): string {
|
||||||
|
// Handle n8n-nodes-base -> nodes-base
|
||||||
|
if (nodeType.startsWith('n8n-nodes-base.')) {
|
||||||
|
return nodeType.replace('n8n-nodes-base.', 'nodes-base.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle @n8n/n8n-nodes-langchain -> nodes-langchain
|
||||||
|
if (nodeType.startsWith('@n8n/n8n-nodes-langchain.')) {
|
||||||
|
return nodeType.replace('@n8n/n8n-nodes-langchain.', 'nodes-langchain.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return unchanged if already normalized or unknown format
|
||||||
|
return nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets alternative node type formats to try for lookups
|
||||||
|
*
|
||||||
|
* @param nodeType The original node type
|
||||||
|
* @returns Array of alternative formats to try
|
||||||
|
*/
|
||||||
|
export function getNodeTypeAlternatives(nodeType: string): string[] {
|
||||||
|
const alternatives: string[] = [];
|
||||||
|
|
||||||
|
// Add lowercase version
|
||||||
|
alternatives.push(nodeType.toLowerCase());
|
||||||
|
|
||||||
|
// 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}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return alternatives;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user