feat: add workflowNodeType field to MCP tool responses for proper n8n workflow creation
- Added workflowNodeType field to all node-returning MCP tools - AI agents now receive both internal format (nodes-base.webhook) and workflow format (n8n-nodes-base.webhook) - Created getWorkflowNodeType() utility to construct proper n8n format from package name - Solves issue where AI agents would search nodes and use wrong format in workflows - No database changes required - uses existing package_name field - Updated: search_nodes, get_node_info, get_node_essentials, get_node_as_tool_info, validate_node_operation - Updated CHANGELOG.md with comprehensive documentation of the changes This completes the fix for issue #71, ensuring AI agents can seamlessly create workflows with the correct node type format without manual intervention.
This commit is contained in:
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
@@ -23,6 +23,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- **Node type utilities** in `src/utils/node-utils.ts`
|
||||
- `normalizeNodeType()` - Converts full package names to database format
|
||||
- `getNodeTypeAlternatives()` - Provides fallback options for edge cases
|
||||
- `getWorkflowNodeType()` - Constructs proper n8n workflow format from database values
|
||||
- **workflowNodeType field** in all MCP tool responses that return node information
|
||||
- AI agents now receive both `nodeType` (internal format) and `workflowNodeType` (n8n format)
|
||||
- Example: `nodeType: "nodes-base.webhook"`, `workflowNodeType: "n8n-nodes-base.webhook"`
|
||||
- Prevents confusion where AI agents would search nodes and use wrong format in workflows
|
||||
- Added to: `search_nodes`, `get_node_info`, `get_node_essentials`, `get_node_as_tool_info`, `validate_node_operation`
|
||||
|
||||
## [2.7.17] - 2025-07-17
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import * as n8nHandlers from './handlers-n8n-manager';
|
||||
import { handleUpdatePartialWorkflow } from './handlers-workflow-diff';
|
||||
import { getToolDocumentation, getToolsOverview } from './tools-documentation';
|
||||
import { PROJECT_VERSION } from '../utils/version';
|
||||
import { normalizeNodeType, getNodeTypeAlternatives } from '../utils/node-utils';
|
||||
import { normalizeNodeType, getNodeTypeAlternatives, getWorkflowNodeType } from '../utils/node-utils';
|
||||
|
||||
interface NodeRow {
|
||||
node_type: string;
|
||||
@@ -383,6 +383,7 @@ export class N8NDocumentationMCPServer {
|
||||
|
||||
return {
|
||||
...node,
|
||||
workflowNodeType: getWorkflowNodeType(node.package, node.nodeType),
|
||||
aiToolCapabilities
|
||||
};
|
||||
}
|
||||
@@ -517,6 +518,7 @@ export class N8NDocumentationMCPServer {
|
||||
query,
|
||||
results: scoredNodes.map(node => ({
|
||||
nodeType: node.node_type,
|
||||
workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type),
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
@@ -596,6 +598,7 @@ export class N8NDocumentationMCPServer {
|
||||
mode: 'FUZZY',
|
||||
results: matchingNodes.map(node => ({
|
||||
nodeType: node.node_type,
|
||||
workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type),
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
@@ -719,6 +722,7 @@ export class N8NDocumentationMCPServer {
|
||||
query,
|
||||
results: rankedNodes.map(node => ({
|
||||
nodeType: node.node_type,
|
||||
workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type),
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
@@ -757,6 +761,7 @@ export class N8NDocumentationMCPServer {
|
||||
query,
|
||||
results: rankedNodes.map(node => ({
|
||||
nodeType: node.node_type,
|
||||
workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type),
|
||||
displayName: node.display_name,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
@@ -1093,6 +1098,7 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
||||
|
||||
const result = {
|
||||
nodeType: node.nodeType,
|
||||
workflowNodeType: getWorkflowNodeType(node.package, node.nodeType),
|
||||
displayName: node.displayName,
|
||||
description: node.description,
|
||||
category: node.category,
|
||||
@@ -1328,6 +1334,7 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
||||
// Add node context to result
|
||||
return {
|
||||
nodeType: node.nodeType,
|
||||
workflowNodeType: getWorkflowNodeType(node.package, node.nodeType),
|
||||
displayName: node.displayName,
|
||||
...validationResult,
|
||||
summary: {
|
||||
@@ -1453,6 +1460,7 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
||||
|
||||
return {
|
||||
nodeType: node.nodeType,
|
||||
workflowNodeType: getWorkflowNodeType(node.package, node.nodeType),
|
||||
displayName: node.displayName,
|
||||
description: node.description,
|
||||
package: node.package,
|
||||
|
||||
@@ -44,3 +44,30 @@ export function getNodeTypeAlternatives(nodeType: string): string[] {
|
||||
|
||||
return alternatives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the workflow node type from package name and normalized node type
|
||||
* This creates the format that n8n expects in workflow definitions
|
||||
*
|
||||
* Examples:
|
||||
* - ('n8n-nodes-base', 'nodes-base.webhook') → 'n8n-nodes-base.webhook'
|
||||
* - ('@n8n/n8n-nodes-langchain', 'nodes-langchain.agent') → '@n8n/n8n-nodes-langchain.agent'
|
||||
*
|
||||
* @param packageName The package name from the database
|
||||
* @param nodeType The normalized node type from the database
|
||||
* @returns The workflow node type for use in n8n workflows
|
||||
*/
|
||||
export function getWorkflowNodeType(packageName: string, nodeType: string): string {
|
||||
// Extract just the node name from the normalized type
|
||||
const nodeName = nodeType.split('.').pop() || nodeType;
|
||||
|
||||
// Construct the full workflow type based on package
|
||||
if (packageName === 'n8n-nodes-base') {
|
||||
return `n8n-nodes-base.${nodeName}`;
|
||||
} else if (packageName === '@n8n/n8n-nodes-langchain') {
|
||||
return `@n8n/n8n-nodes-langchain.${nodeName}`;
|
||||
}
|
||||
|
||||
// Fallback for unknown packages - return as is
|
||||
return nodeType;
|
||||
}
|
||||
Reference in New Issue
Block a user