docs/local/DEEP_DIVE_ANALYSIS_2025-10-02.md
Analysis Period: September 26 - October 2, 2025 (6 days) Data Volume: 212,375 events | 5,751 workflows | 2,119 unique users Database: Supabase telemetry with 15 analytical views Analyst: Claude Code with Supabase MCP integration Date: October 2, 2025
n8n-mcp has achieved strong adoption with 2,119 users generating 212K+ events in 6 days. The system demonstrates excellent reliability (96-100% success rates for most tools) but has critical pain points that are blocking users and degrading the AI agent experience. The upcoming refactor should focus on:
Key Metrics:
EXCELLENT (95-100% success):
n8n_update_partial_workflow - 10,177 calls, 98.7% success, 846 userssearch_nodes - 8,839 calls, 99.8% success, 1,283 usersn8n_create_workflow - 6,046 calls, 96.1% success, 1,305 usersn8n_validate_workflow - 3,222 calls, 99.8% success, 597 usersn8n_get_workflow - 3,368 calls, 99.8% success, 790 usersn8n_update_full_workflow - 2,640 calls, 99.4% success, 486 userstools_documentation - 1,886 calls, 100% success, 879 usersvalidate_workflow - 1,667 calls, 95.4% success, 472 usersGOOD (80-95% success):
get_node_essentials - 4,909 calls, 90.2% success, 921 users (9.8% failure)get_node_documentation - 1,919 calls, 92.9% success, 657 users (7.1% failure)validate_node_operation - 998 calls, 88.6% success, 240 users (11.4% failure)list_ai_tools - 234 calls, 84.2% success, 184 users (15.8% failure)get_node_info - 1,988 calls, 82.3% success, 677 users (17.7% failure)POOR (50-80% success):
get_node_for_task - 392 calls, 72.2% success, 197 users (27.8% failure)Ultra-Fast (<10ms avg):
get_node_essentials: 3.27ms avg (median: 1ms)get_node_info: 4.78ms avg (median: 1ms)get_node_documentation: 2.16ms avg (median: 1ms)tools_documentation: 3.42ms avg (median: 1ms)validate_node_minimal: 1.79ms avg (median: 1ms)Fast (10-100ms avg):
search_nodes: 20.47ms avg (median: 5ms, p95: 84ms)validate_workflow: 31.59ms avg (median: 12ms, p95: 103ms)list_nodes: 41.86ms avg (median: 11ms, p95: 196ms)Acceptable (100-500ms avg):
n8n_get_workflow: 248.79ms avg (median: 111ms, p95: 830ms)n8n_validate_workflow: 229.37ms avg (median: 106ms, p95: 722ms)n8n_update_full_workflow: 302.70ms avg (median: 119ms, p95: 1,069ms)n8n_delete_workflow: 308.85ms avg (median: 166ms, p95: 950ms)n8n_create_workflow: 333.37ms avg (median: 85ms, p95: 1,251ms)n8n_list_workflows: 476.05ms avg (median: 231ms, p95: 1,465ms)n8n_autofix_workflow: 486.49ms avg (median: 174ms, p95: 1,152ms)Slow (>500ms avg):
n8n_get_execution: 670.35ms avg (median: 121ms, p95: 1,166ms)n8n_trigger_webhook_workflow: 1,884.67ms avg (median: 157ms, p95: 4,865ms)FINDING #1: Node information tools have systematic TypeError issues
get_node_essentials: 483 failures (10% of calls)get_node_info: 352 failures (18% of calls)get_node_documentation: 136 failures (7% of calls)FINDING #2: Task-based node discovery is failing 28% of the time
get_node_for_task has the worst success rate (72%)FINDING #3: Performance is excellent across the board
FINDING #4: Workflow management tools have perfect reliability
n8n_list_workflows: 100% success (1,489 calls)n8n_health_check: 100% success (1,304 calls)n8n_list_executions: 100% success (1,297 calls)n8n_delete_workflow: 100% success (1,230 calls)CRITICAL ISSUE: 5,000+ validation errors from a single root cause
Error: Invalid node type: "nodes-base.set". Use "n8n-nodes-base.set" instead.
Breakdown by error type:
4,800 occurrences: "Invalid node type" prefix errors across Node0-Node19
nodes-base.X instead of n8n-nodes-base.X2,500 occurrences: "Multi-node workflow has no connections"
58 occurrences: "Single-node workflows are only valid for webhook endpoints"
22 occurrences: Duplicate node ID: "undefined"
Why AI agents produce nodes-base.X instead of n8n-nodes-base.X:
Why the system doesn't auto-correct:
From CHANGELOG 2.14.2:
"Fixed validation false positives for Google Drive nodes with 'fileFolder' resource
- Added node type normalization to handle both
n8n-nodes-base.andnodes-base.prefixes correctly"
Analysis: A fix was attempted in 2.14.2, but it's incomplete or not applied universally. The normalization logic exists but isn't being called in all validation paths.
User Experience:
Quantitative Impact:
Why This Is Critical:
Connection Validation:
Node Configuration:
| Segment | Users | % | Events | Avg Events | Workflows | Success Rate |
|---|---|---|---|---|---|---|
| Power Users (1000+) | 12 | 0.6% | 25,346 | 2,112 | 33 | 97.1% |
| Heavy Users (500-999) | 47 | 2.2% | 31,608 | 673 | 18 | 98.0% |
| Regular Users (100-499) | 516 | 24.3% | 102,931 | 199 | 7 | 96.5% |
| Active Users (20-99) | 919 | 43.4% | 47,768 | 52 | 2 | 97.0% |
| Casual Users (<20) | 625 | 29.5% | 4,958 | 8 | 1 | 97.6% |
| TOTAL | 2,119 | 100% | 212,611 | 100 | - | 97.0% |
INSIGHT #1: Extreme power law distribution
Implications:
INSIGHT #2: Regular users (516) are the core audience
INSIGHT #3: Consistent success rates across segments
INSIGHT #4: Workflow creation correlates with engagement
| Date | Events | Users | Events/User | Growth |
|---|---|---|---|---|
| Sep 26 | 16,334 | 958 | 17.0 | baseline |
| Sep 27 | 26,042 | 2,075 | 12.6 | +59% events |
| Sep 28 | 35,687 | 2,655 | 13.4 | +37% events |
| Sep 29 | 40,361 | 3,039 | 13.3 | +13% events (peak) |
| Sep 30 | 39,833 | 3,319 | 12.0 | -1% events |
| Oct 1 | 39,854 | 3,528 | 11.3 | 0% events |
| Oct 2 | 14,500 | 1,057 | 13.7 | partial day |
Growth Analysis:
Interpretation:
Top 15 Tool Sequences (all show 300s = 5 min time delta):
| Rank | Sequence | Count | Users | Pattern |
|---|---|---|---|---|
| 1 | update_partial_workflow → update_partial_workflow | 549 | 153 | Iterative refinement |
| 2 | create_workflow → update_partial_workflow | 297 | 118 | Create then refine |
| 3 | update_partial_workflow → get_workflow | 265 | 91 | Update then verify |
| 4 | create_workflow → create_workflow | 237 | 97 | Multiple attempts |
| 5 | create_workflow → get_workflow | 185 | 81 | Create then inspect |
| 6 | create_workflow → search_nodes | 166 | 72 | Create then discover |
| 7 | validate_workflow → update_partial_workflow | 161 | 63 | Validate then fix |
| 8 | validate_workflow → validate_workflow | 152 | 44 | Re-validation |
| 9 | validate_workflow → get_workflow | 134 | 53 | Validate then inspect |
| 10 | update_partial_workflow → create_workflow | 130 | 59 | Update then recreate |
| 11 | get_workflow → update_partial_workflow | 117 | 50 | Inspect then update |
| 12 | update_full_workflow → update_partial_workflow | 98 | 41 | Full to partial update |
| 13 | update_partial_workflow → search_nodes | 94 | 42 | Update then discover |
| 14 | get_workflow → create_workflow | 87 | 42 | Inspect then recreate |
| 15 | create_workflow → tools_documentation | 85 | 36 | Create then learn |
INSIGHT #1: AI agents iterate heavily on workflows
update → update → update (549 occurrences)Implication: The diff-based update system (v2.7.0) is CRUCIAL for token efficiency
INSIGHT #2: All transitions show 5-minute time deltas
is_slow_transition: trueRecommendation: Add fine-grained timing (see T1 in Telemetry Enhancements)
INSIGHT #3: Node discovery happens AFTER workflow creation
create_workflow → search_nodes (166 occurrences)Opportunity: Proactive node suggestions during creation (see P1-R5)
INSIGHT #4: Validation drives updates
validate_workflow → update_partial_workflow (161 occurrences)validate_workflow → validate_workflow (152 occurrences)Quality: This is GOOD behavior (AI agents using validation to improve) Optimization: Better validation error messages → fewer iterations (see P1-R6)
Pattern A: Create-Update-Validate Loop
create_workflow → update_partial_workflow → validate_workflow → update_partial_workflow
Pattern B: Inspect-Modify-Deploy
get_workflow → update_partial_workflow → validate_workflow → get_workflow
Pattern C: Search-Create-Refine
search_nodes → create_workflow → update_partial_workflow → validate_workflow
Tools used within 5 minutes BEFORE workflow creation:
| Tool | Occurrences | Users | Conversion Rate |
|---|---|---|---|
update_partial_workflow | 6,271 | 547 | High |
search_nodes | 6,099 | 901 | High |
get_node_essentials | 3,361 | 649 | Medium |
create_workflow | 2,810 | 742 | Medium (re-creation) |
get_workflow | 2,057 | 512 | Medium |
validate_workflow | 2,014 | 417 | Medium |
get_node_documentation | 1,301 | 456 | Low |
tools_documentation | 1,290 | 596 | Low |
Interpretation:
| Complexity | Count | % | Avg Nodes | Median | Triggers | Webhooks |
|---|---|---|---|---|---|---|
| Simple | 4,290 | 75% | 5.5 | 5 | 1,330 (31%) | 1,330 (31%) |
| Medium | 1,282 | 22% | 14.0 | 13 | 424 (33%) | 424 (33%) |
| Complex | 187 | 3% | 27.5 | 23 | 71 (38%) | 71 (38%) |
| TOTAL | 5,759 | 100% | 8.2 | 6 | 1,825 (32%) | 1,825 (32%) |
Complexity Definitions:
FINDING #1: 75% of workflows are simple
FINDING #2: Complex workflows are rare but important
FINDING #3: Webhook usage is consistent across complexity
Top 20 Nodes by Workflow Count:
| Rank | Node Type | Workflows | % | Users | Avg Workflow Size |
|---|---|---|---|---|---|
| 1 | n8n-nodes-base.code | 3,051 | 53% | 1,056 | 9.4 |
| 2 | n8n-nodes-base.httpRequest | 2,686 | 47% | 1,033 | 9.6 |
| 3 | n8n-nodes-base.webhook | 1,812 | 32% | 750 | 8.5 |
| 4 | n8n-nodes-base.set | 1,738 | 30% | 742 | 9.2 |
| 5 | n8n-nodes-base.if | 1,400 | 24% | 653 | 12.2 |
| 6 | n8n-nodes-base.manualTrigger | 1,391 | 24% | 590 | 7.9 |
| 7 | n8n-nodes-base.respondToWebhook | 1,113 | 19% | 484 | 8.7 |
| 8 | @n8n/n8n-nodes-langchain.agent | 884 | 15% | 403 | 9.7 |
| 9 | n8n-nodes-base.scheduleTrigger | 825 | 14% | 412 | 9.5 |
| 10 | n8n-nodes-base.googleSheets | 732 | 13% | 324 | 10.5 |
| 11 | n8n-nodes-base.merge | 599 | 10% | 311 | 13.8 |
| 12 | @n8n/n8n-nodes-langchain.lmChatOpenAi | 564 | 10% | 268 | 10.6 |
| 13 | n8n-nodes-base.switch | 534 | 9% | 262 | 13.7 |
| 14 | n8n-nodes-base.openAi | 486 | 8% | 261 | 10.1 |
| 15 | n8n-nodes-base.splitInBatches | 457 | 8% | 229 | 13.2 |
| 16 | n8n-nodes-base.telegram | 416 | 7% | 168 | 10.0 |
| 17 | n8n-nodes-base.function | 414 | 7% | 162 | 9.6 |
| 18 | n8n-nodes-base.gmail | 400 | 7% | 212 | 9.5 |
| 19 | n8n-nodes-base.cron | 380 | 7% | 182 | 9.2 |
| 20 | n8n-nodes-base.noOp | 322 | 6% | 174 | 10.9 |
INSIGHT #1: Code node dominates (53% of workflows)
INSIGHT #2: HTTP Request is in nearly half of workflows (47%)
INSIGHT #3: LangChain nodes show strong adoption (15%)
langchain.agent in 884 workflowslmChatOpenAi in 564 workflowsINSIGHT #4: Average workflow size correlates with node type
Top 20 Node Pairs:
| Rank | Node 1 | Node 2 | Co-occurrence | Users | Avg Size | Pattern |
|---|---|---|---|---|---|---|
| 1 | code | httpRequest | 1,646 | 686 | 10.4 | Data transformation + API |
| 2 | webhook | respondToWebhook | 1,043 | 452 | 8.8 | Standard webhook pattern |
| 3 | code | webhook | 1,008 | 442 | 9.6 | Custom webhook logic |
| 4 | code | if | 894 | 437 | 12.9 | Conditional with custom logic |
| 5 | httpRequest | webhook | 845 | 404 | 10.5 | Webhook-triggered API calls |
| 6 | httpRequest | set | 841 | 431 | 10.7 | API response processing |
| 7 | httpRequest | if | 815 | 420 | 13.4 | Conditional API logic |
| 8 | code | manualTrigger | 731 | 321 | 9.7 | Manual testing workflows |
| 9 | httpRequest | manualTrigger | 706 | 328 | 9.1 | Manual API testing |
| 10 | code | set | 677 | 339 | 11.6 | Data manipulation |
| 11 | code | respondToWebhook | 617 | 285 | 9.8 | Webhook responses |
| 12 | code | scheduleTrigger | 585 | 290 | 10.3 | Scheduled automation |
| 13 | manualTrigger | set | 569 | 290 | 8.6 | Simple manual workflows |
| 14 | if | set | 545 | 291 | 13.0 | Conditional data setting |
| 15 | httpRequest | respondToWebhook | 534 | 263 | 10.0 | API-based webhooks |
| 16 | webhook | set | 516 | 289 | 9.9 | Webhook data processing |
| 17 | httpRequest | scheduleTrigger | 511 | 270 | 10.4 | Scheduled API calls |
| 18 | webhook | if | 477 | 277 | 12.7 | Conditional webhooks |
| 19 | code | googleSheets | 475 | 212 | 11.4 | Sheets data processing |
| 20 | agent | lmChatOpenAi | 475 | 222 | 10.1 | AI agent workflows |
Pattern A: The "Transform-and-Call" Pattern
code + httpRequest (1,646 workflows)Pattern B: The "Webhook Handler" Pattern
webhook + respondToWebhook (1,043 workflows)Pattern C: The "Conditional Integration" Pattern
httpRequest + if + set (combined ~2,000 workflows)Pattern D: The "AI Agent" Pattern
agent + lmChatOpenAi + memoryBufferWindow (475 workflows)Top nodes in complex workflows (21+ nodes):
| Rank | Node Type | Count | Avg Size |
|---|---|---|---|
| 1 | code | 139 | 26.7 |
| 2 | httpRequest | 125 | 27.6 |
| 3 | if | 111 | 27.4 |
| 4 | set | 87 | 28.0 |
| 5 | switch | 74 | 27.9 |
| 6 | webhook | 68 | 29.5 |
| 7 | merge | 62 | 27.1 |
| 8 | splitInBatches | 50 | 25.6 |
Insight: Complex workflows use the same core nodes, just more of them
Top 20 Configurations:
| Platform | Arch | Version | Sessions | Users | % |
|---|---|---|---|---|---|
| Linux | x64 | 2.14.0 | 1,488 | 242 | 34% |
| Linux | arm64 | 2.14.0 | 190 | 135 | 4% |
| Windows | x64 | 2.14.1 | 115 | 79 | 3% |
| Windows | x64 | 2.14.1 | 95 | 53 | 2% |
| macOS | arm64 | 2.14.1 | 77 | 51 | 2% |
| Windows | x64 | 2.14.1 | 70 | 41 | 2% |
| macOS | arm64 | 2.14.1 | 68 | 43 | 2% |
| Windows | x64 | 2.14.1 | 60 | 46 | 1% |
| Linux | x64 | 2.14.5 | 54 | 30 | 1% |
| macOS | arm64 | 2.14.1 | 51 | 26 | 1% |
Aggregated by Platform:
| Version | Total Sessions | Estimated Users | Release Date |
|---|---|---|---|
| 2.14.0 | 1,678 | 377 | Sep 26 |
| 2.14.1 | 780+ | 500+ | Sep 26 |
| 2.14.2 | ~50 | ~40 | Sep 29 |
| 2.14.3 | ~30 | ~25 | Sep 29 |
| 2.14.4 | 29 | 27 | Sep 30 |
| 2.14.5 | 54 | 30 | Sep 30 |
| 2.14.6 | 74 | 56 | Oct 1 |
FINDING #1: Majority stuck on 2.14.0 (37% of sessions)
FINDING #2: Slow version adoption
FINDING #3: Linux dominates (40% of sessions)
FINDING #4: Node.js version fragmentation
R1: Version update notifications
R2: Docker image optimization
R3: Breaking change policy
Error Distribution (from error logs):
| Tool | TypeError Count | Affected Users | % Failure |
|---|---|---|---|
get_node_essentials | ~350 | 10+ | 9.8% |
get_node_info | ~250 | 12+ | 17.7% |
get_node_documentation | ~100 | 8+ | 7.1% |
| TOTAL | ~700 | ~30 | varies |
From CHANGELOG 2.14.0:
"Fixed TypeErrors in
get_node_info,get_node_essentials, andget_node_documentationtools that were affecting 50% of calls" "Added null safety checks for undefined node properties"
Analysis:
Example Error Pattern:
// Fails when node.properties.description is undefined
const description = node.properties.description.text;
// Should be:
const description = node?.properties?.description?.text ?? 'No description';
Pattern:
n8n_create_workflow: 237 failures (3.9% failure rate)ValidationErrortool_executionRoot causes (from validation analysis):
Node type prefix errors (80% of validation errors)
nodes-base.X vs n8n-nodes-base.XMissing connections (10% of validation errors)
Duplicate node IDs (5% of validation errors)
Other validation issues (5%)
Pattern:
get_node_for_task: 109 failures (27.8% failure rate)Probable causes:
Example failing queries (inferred):
Low-frequency errors (<10 occurrences):
These are expected in production and handled gracefully
Problem: 4,800+ validation errors from nodes-base.X vs n8n-nodes-base.X
Impact:
Solution:
// src/services/workflow-validator.ts
export function normalizeNodeTypes(workflow: any): any {
const normalized = { ...workflow };
if (normalized.nodes) {
normalized.nodes = normalized.nodes.map((node: any) => ({
...node,
type: normalizeNodeType(node.type)
}));
}
return normalized;
}
function normalizeNodeType(type: string): string {
// Fix common AI-generated abbreviations
const prefixMap: Record<string, string> = {
'nodes-base.': 'n8n-nodes-base.',
'nodes-langchain.': '@n8n/n8n-nodes-langchain.',
'n8n-nodes-langchain.': '@n8n/n8n-nodes-langchain.'
};
for (const [short, full] of Object.entries(prefixMap)) {
if (type.startsWith(short)) {
return type.replace(short, full);
}
}
return type;
}
Apply in handlers:
// src/mcp/handlers-n8n-manager.ts
export async function handleCreateWorkflow(params: any): Promise<McpToolResponse> {
// Normalize before validation
const normalizedWorkflow = normalizeNodeTypes(params);
const validation = await validateWorkflow(normalizedWorkflow);
if (!validation.valid) {
return { success: false, error: validation.errors };
}
// Use normalized workflow
return await createWorkflow(normalizedWorkflow);
}
export async function handleUpdateFullWorkflow(params: any): Promise<McpToolResponse> {
const normalizedWorkflow = normalizeNodeTypes(params);
// ... rest of handler
}
Testing:
// tests/unit/services/workflow-normalizer.test.ts
describe('normalizeNodeTypes', () => {
it('should normalize nodes-base prefix', () => {
const workflow = {
nodes: [
{ id: '1', type: 'nodes-base.set', parameters: {} }
]
};
const result = normalizeNodeTypes(workflow);
expect(result.nodes[0].type).toBe('n8n-nodes-base.set');
});
it('should handle already-normalized types', () => {
const workflow = {
nodes: [
{ id: '1', type: 'n8n-nodes-base.set', parameters: {} }
]
};
const result = normalizeNodeTypes(workflow);
expect(result.nodes[0].type).toBe('n8n-nodes-base.set');
});
it('should normalize langchain nodes', () => {
const workflow = {
nodes: [
{ id: '1', type: 'nodes-langchain.agent', parameters: {} }
]
};
const result = normalizeNodeTypes(workflow);
expect(result.nodes[0].type).toBe('@n8n/n8n-nodes-langchain.agent');
});
});
Effort: 2-4 hours Risk: Low (only adds normalization, doesn't change validation logic) Files:
src/services/workflow-validator.ts (new helper)src/mcp/handlers-n8n-manager.ts (apply in handlers)tests/unit/services/workflow-normalizer.test.ts (new tests)Problem: 10-18% failure rate for get_node_essentials, get_node_info, get_node_documentation
Impact:
Solution: Comprehensive null-safety refactor
Step 1: Update repository methods
// src/database/node-repository.ts
export class NodeRepository {
getNodeEssentials(nodeType: string): NodeEssentials | null {
try {
const node = this.db.prepare(`
SELECT * FROM nodes WHERE type = ?
`).get(nodeType);
if (!node) {
return null;
}
// Safe property access with defaults
return {
type: node.type ?? 'unknown',
displayName: node.displayName ?? node.name ?? 'Unknown Node',
description: this.extractDescription(node),
category: node.category ?? 'Uncategorized',
icon: node.icon ?? 'fa:question',
inputs: this.parseJSON(node.inputs, []),
outputs: this.parseJSON(node.outputs, []),
properties: this.extractEssentialProperties(node)
};
} catch (error) {
this.logger.error('Error getting node essentials', { nodeType, error });
return null;
}
}
private extractDescription(node: any): string {
// Try multiple possible locations for description
if (node.description) return node.description;
if (node.properties?.description?.text) return node.properties.description.text;
if (node.properties?.description) return node.properties.description;
if (node.subtitle) return node.subtitle;
return 'No description available';
}
private parseJSON<T>(value: any, defaultValue: T): T {
if (!value) return defaultValue;
try {
return typeof value === 'string' ? JSON.parse(value) : value;
} catch {
return defaultValue;
}
}
private extractEssentialProperties(node: any): any[] {
try {
const props = this.parseJSON(node.properties, []);
return props.map((prop: any) => ({
name: prop.name ?? 'unknown',
displayName: prop.displayName ?? prop.name ?? 'Unknown',
type: prop.type ?? 'string',
required: prop.required ?? false,
default: prop.default ?? null,
description: prop.description ?? ''
}));
} catch {
return [];
}
}
}
Step 2: Update handlers with error handling
// src/mcp/handlers.ts
export async function handleGetNodeEssentials(params: { nodeType: string }): Promise<McpToolResponse> {
const { nodeType } = params;
// Validate input
if (!nodeType || typeof nodeType !== 'string') {
return {
success: false,
error: 'Invalid nodeType parameter'
};
}
try {
const essentials = await nodeRepository.getNodeEssentials(nodeType);
if (!essentials) {
return {
success: false,
error: `Node type "${nodeType}" not found. Use search_nodes to find available nodes.`
};
}
return {
success: true,
data: essentials
};
} catch (error) {
return {
success: false,
error: `Failed to get node essentials: ${error.message}`
};
}
}
Step 3: Add comprehensive tests
// tests/unit/database/node-repository.test.ts
describe('NodeRepository - Null Safety', () => {
it('should handle node with missing description', () => {
const node = { type: 'test.node', name: 'Test' };
db.prepare('INSERT INTO nodes VALUES (?, ?, NULL)').run(node.type, node.name);
const result = repository.getNodeEssentials('test.node');
expect(result).not.toBeNull();
expect(result.description).toBe('No description available');
});
it('should handle node with malformed JSON properties', () => {
const node = { type: 'test.node', properties: 'invalid json' };
db.prepare('INSERT INTO nodes VALUES (?, ?, ?)').run(node.type, node.name, node.properties);
const result = repository.getNodeEssentials('test.node');
expect(result).not.toBeNull();
expect(result.properties).toEqual([]);
});
it('should return null for non-existent node', () => {
const result = repository.getNodeEssentials('non.existent');
expect(result).toBeNull();
});
});
Effort: 1 day (8 hours) Risk: Medium (changes core repository methods, needs thorough testing) Files:
src/database/node-repository.ts (refactor)src/mcp/handlers.ts (update error handling)tests/unit/database/node-repository.test.ts (comprehensive tests)tests/unit/mcp/handlers.test.ts (update tests)Success Criteria:
get_node_essentials failure rate: 10% → <1%get_node_info failure rate: 18% → <1%get_node_documentation failure rate: 7% → <1%get_node_for_task success rateProblem: 27.8% failure rate (worst-performing tool)
Impact:
Solution: Multi-pronged enhancement
Step 1: Expand task library
// src/services/task-templates.ts
export const TASK_LIBRARY = {
// HTTP & API
'http_request': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
'api_call': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
'make_http_request': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
'fetch_data': { node: 'n8n-nodes-base.httpRequest', priority: 2 },
// Data transformation
'transform_data': { node: 'n8n-nodes-base.code', priority: 1 },
'process_json': { node: 'n8n-nodes-base.code', priority: 1 },
'manipulate_data': { node: 'n8n-nodes-base.set', priority: 2 },
'set_values': { node: 'n8n-nodes-base.set', priority: 1 },
// Email
'send_email': { node: 'n8n-nodes-base.emailSend', priority: 1 },
'email_notification': { node: 'n8n-nodes-base.emailSend', priority: 1 },
'receive_email': { node: 'n8n-nodes-base.emailReadImap', priority: 1 },
// Webhooks
'webhook': { node: 'n8n-nodes-base.webhook', priority: 1 },
'receive_webhook': { node: 'n8n-nodes-base.webhook', priority: 1 },
'respond_to_webhook': { node: 'n8n-nodes-base.respondToWebhook', priority: 1 },
// ... expand to 100+ tasks
};
Step 2: Add fuzzy matching
// src/services/discovery-service.ts
import Fuse from 'fuse.js';
export class DiscoveryService {
private taskIndex: Fuse<TaskDefinition>;
constructor() {
// Build fuzzy search index
this.taskIndex = new Fuse(Object.entries(TASK_LIBRARY), {
keys: ['0'], // Task name
threshold: 0.4, // Allow some typos
distance: 100
});
}
getNodeForTask(taskDescription: string): TaskMatch[] {
// 1. Try exact match
const exactMatch = TASK_LIBRARY[taskDescription.toLowerCase()];
if (exactMatch) {
return [{
node: exactMatch.node,
confidence: 1.0,
reason: 'Exact task match'
}];
}
// 2. Try fuzzy match
const fuzzyMatches = this.taskIndex.search(taskDescription);
if (fuzzyMatches.length > 0) {
return fuzzyMatches.slice(0, 3).map(match => ({
node: match.item[1].node,
confidence: 1 - match.score,
reason: `Similar to "${match.item[0]}"`
}));
}
// 3. Fallback to keyword search in node descriptions
return this.searchNodesByKeywords(taskDescription);
}
private searchNodesByKeywords(query: string): TaskMatch[] {
// Use existing search_nodes functionality
const results = nodeRepository.searchNodes(query, { limit: 3 });
return results.map(node => ({
node: node.type,
confidence: 0.5,
reason: `Found by keyword search: "${query}"`
}));
}
}
Step 3: Return multiple suggestions
// src/mcp/handlers.ts
export async function handleGetNodeForTask(params: { task: string }): Promise<McpToolResponse> {
const { task } = params;
try {
const matches = discoveryService.getNodeForTask(task);
if (matches.length === 0) {
return {
success: false,
error: `No node found for task "${task}". Try search_nodes with keywords instead.`,
suggestions: [
'Use search_nodes to explore available nodes',
'Check list_tasks to see predefined task names'
]
};
}
return {
success: true,
data: {
primaryMatch: matches[0],
alternativeMatches: matches.slice(1),
totalMatches: matches.length
}
};
} catch (error) {
return {
success: false,
error: `Failed to find node for task: ${error.message}`
};
}
}
Step 4: Testing
// tests/unit/services/discovery-service.test.ts
describe('DiscoveryService - Task Matching', () => {
it('should find exact task match', () => {
const result = service.getNodeForTask('send_email');
expect(result[0].node).toBe('n8n-nodes-base.emailSend');
expect(result[0].confidence).toBe(1.0);
});
it('should handle typos with fuzzy matching', () => {
const result = service.getNodeForTask('send emial'); // typo
expect(result[0].node).toBe('n8n-nodes-base.emailSend');
expect(result[0].confidence).toBeGreaterThan(0.7);
});
it('should return multiple suggestions', () => {
const result = service.getNodeForTask('process data');
expect(result.length).toBeGreaterThan(1);
expect(result).toContainEqual(
expect.objectContaining({ node: 'n8n-nodes-base.code' })
);
});
it('should fallback to keyword search', () => {
const result = service.getNodeForTask('sheets manipulation');
expect(result.some(r => r.node.includes('googleSheets'))).toBe(true);
});
});
Effort: 3 days (24 hours)
Risk: Low (enhances existing functionality)
Dependencies: fuse.js (fuzzy search library)
Files:
src/services/task-templates.ts (expand library)src/services/discovery-service.ts (new service)src/mcp/handlers.ts (update handler)tests/unit/services/discovery-service.test.ts (comprehensive tests)Success Criteria:
get_node_for_task success rate: 72% → 95%1. Auto-normalize node type prefixes (P0-R1)
workflow-validator.ts, handlers-n8n-manager.ts2. Complete null-safety audit (P0-R2)
node-repository.ts, handlers.ts3. Expand task discovery library (P0-R3)
task-templates.ts, discovery-service.tsExpected Overall Impact: