mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-01-30 06:22:04 +00:00
* feat: Remove 9 low-value tools and consolidate n8n_health_check (v2.25.0) Telemetry-driven tool cleanup to improve API clarity: **Removed Tools (9):** - list_nodes - Use search_nodes instead - list_ai_tools - Use search_nodes with isAITool filter - list_tasks - Low usage (0.02%) - get_database_statistics - Use n8n_health_check - list_templates - Use search_templates or get_templates_for_task - get_node_as_tool_info - Documented in get_node - validate_workflow_connections - Use validate_workflow - validate_workflow_expressions - Use validate_workflow - n8n_list_available_tools - Use n8n_health_check - n8n_diagnostic - Merged into n8n_health_check **Consolidated Tool:** - n8n_health_check now supports mode='diagnostic' for detailed troubleshooting **Tool Count:** - Before: 38 tools - After: 31 tools (18% reduction) Concieved by Romuald Członkowski - www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: cleanup stale references and update tests after tool removal - Remove handleListAvailableTools dead code from handlers-n8n-manager.ts - Update error messages to reference n8n_health_check(mode="diagnostic") instead of n8n_diagnostic - Update tool counts in diagnostic messages (14 doc tools, 31 total) - Fix error-handling.test.ts to use valid tools (search_nodes, tools_documentation) - Remove obsolete list-tools.test.ts integration tests - Remove unused ListToolsResponse type from response-types.ts - Update tools.ts QUICK REFERENCE to remove list_nodes references - Update tools-documentation.ts to remove references to removed tools - Update tool-docs files to remove stale relatedTools references - Fix tools.test.ts to not test removed tools (list_nodes, list_ai_tools, etc.) - Fix parameter-validation.test.ts to not test removed tools - Update handlers-n8n-manager.test.ts error message expectations All 399 MCP unit tests now pass. Conceived by Romuald Członkowski - www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: update integration tests to use valid tools after v2.25.0 removal Replaced all references to removed tools in integration tests: - list_nodes -> search_nodes - get_database_statistics -> tools_documentation - list_ai_tools -> search_nodes/tools_documentation - list_tasks -> tools_documentation - get_node_as_tool_info -> removed test section Updated test files: - tests/integration/mcp-protocol/basic-connection.test.ts - tests/integration/mcp-protocol/performance.test.ts - tests/integration/mcp-protocol/session-management.test.ts - tests/integration/mcp-protocol/test-helpers.ts - tests/integration/mcp-protocol/tool-invocation.test.ts - tests/integration/telemetry/mcp-telemetry.test.ts - tests/unit/mcp/disabled-tools.test.ts - tests/unit/mcp/tools-documentation.test.ts Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Tool consolidation v2.26.0 - reduce tools by 38% (31 → 19) Major consolidation of MCP tools using mode-based parameters for better AI agent ergonomics: Node Tools: - get_node_documentation → get_node with mode='documentation' - search_node_properties → get_node with mode='search_properties' - get_property_dependencies → removed Validation Tools: - validate_node_operation + validate_node_minimal → validate_node with mode param Template Tools: - list_node_templates → search_templates with searchMode='nodes' - search_templates_by_metadata → search_templates with searchMode='metadata' - get_templates_for_task → search_templates with searchMode='task' Workflow Getters: - n8n_get_workflow_details/structure/minimal → n8n_get_workflow with mode param Execution Tools: - n8n_list/get/delete_execution → n8n_executions with action param Test updates for all consolidated tools. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en * docs: comprehensive README update for v2.26.0 tool consolidation - Quick Start: Added hosted service (dashboard.n8n-mcp.com) as primary option - Self-hosting: Renamed options to A (npx), B (Docker), C (Local), D (Railway) - Removed: "Memory Leak Fix (v2.20.2)" section (outdated) - Removed: "Known Issues" section (outdated container management) - Claude Project Setup: Updated all tool references to v2.26.0 consolidated tools - validate_node({mode: 'minimal'|'full'}) instead of separate tools - search_templates({searchMode: ...}) unified template search - get_node({mode: 'docs'|'search_properties'}) for documentation - n8n_executions({action: ...}) unified execution management - Available MCP Tools: Updated to show 19 consolidated tools (7 core + 12 mgmt) - Recent Updates: Simplified to just link to CHANGELOG.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en * fix: update tool count from 31 to 19 in diagnostic message 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(tests): update tool count expectations for v2.26.0 Update handlers-n8n-manager.test.ts to expect new consolidated tool counts (7/12/19) after v2.26.0 tool consolidation. Conceived by Romuald Członkowski - www.aiadvisors.pl/en 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
374 lines
14 KiB
TypeScript
374 lines
14 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import {
|
|
getToolDocumentation,
|
|
getToolsOverview,
|
|
searchToolDocumentation,
|
|
getToolsByCategory,
|
|
getAllCategories
|
|
} from '@/mcp/tools-documentation';
|
|
|
|
// Mock the tool-docs import
|
|
vi.mock('@/mcp/tool-docs', () => ({
|
|
toolsDocumentation: {
|
|
search_nodes: {
|
|
name: 'search_nodes',
|
|
category: 'discovery',
|
|
essentials: {
|
|
description: 'Search nodes by keywords',
|
|
keyParameters: ['query', 'mode', 'limit'],
|
|
example: 'search_nodes({query: "slack"})',
|
|
performance: 'Instant (<10ms)',
|
|
tips: ['Use single words for precision', 'Try FUZZY mode for typos']
|
|
},
|
|
full: {
|
|
description: 'Full-text search across all n8n nodes with multiple matching modes',
|
|
parameters: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'Search terms',
|
|
required: true
|
|
},
|
|
mode: {
|
|
type: 'string',
|
|
description: 'Search mode',
|
|
enum: ['OR', 'AND', 'FUZZY'],
|
|
default: 'OR'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Max results',
|
|
default: 20
|
|
}
|
|
},
|
|
returns: 'Array of matching nodes with metadata',
|
|
examples: [
|
|
'search_nodes({query: "webhook"})',
|
|
'search_nodes({query: "http request", mode: "AND"})'
|
|
],
|
|
useCases: ['Finding integration nodes', 'Discovering available triggers'],
|
|
performance: 'Instant - uses in-memory index',
|
|
bestPractices: ['Start with single words', 'Use FUZZY for uncertain names'],
|
|
pitfalls: ['Overly specific queries may return no results'],
|
|
relatedTools: ['get_node', 'get_node_documentation']
|
|
}
|
|
},
|
|
validate_workflow: {
|
|
name: 'validate_workflow',
|
|
category: 'validation',
|
|
essentials: {
|
|
description: 'Validate complete workflow structure',
|
|
keyParameters: ['workflow', 'options'],
|
|
example: 'validate_workflow(workflow)',
|
|
performance: 'Moderate (100-500ms)',
|
|
tips: ['Run before deployment', 'Check all validation types']
|
|
},
|
|
full: {
|
|
description: 'Comprehensive workflow validation',
|
|
parameters: {
|
|
workflow: {
|
|
type: 'object',
|
|
description: 'Workflow JSON',
|
|
required: true
|
|
},
|
|
options: {
|
|
type: 'object',
|
|
description: 'Validation options'
|
|
}
|
|
},
|
|
returns: 'Validation results with errors and warnings',
|
|
examples: ['validate_workflow(workflow)'],
|
|
useCases: ['Pre-deployment checks', 'CI/CD validation'],
|
|
performance: 'Depends on workflow complexity',
|
|
bestPractices: ['Validate before saving', 'Fix errors first'],
|
|
pitfalls: ['Large workflows may take time'],
|
|
relatedTools: ['validate_node']
|
|
}
|
|
},
|
|
get_node_essentials: {
|
|
name: 'get_node_essentials',
|
|
category: 'configuration',
|
|
essentials: {
|
|
description: 'Get essential node properties only',
|
|
keyParameters: ['nodeType'],
|
|
example: 'get_node_essentials("nodes-base.slack")',
|
|
performance: 'Fast (<100ms)',
|
|
tips: ['Use this before get_node_info', 'Returns 95% smaller payload']
|
|
},
|
|
full: {
|
|
description: 'Returns 10-20 most important properties',
|
|
parameters: {
|
|
nodeType: {
|
|
type: 'string',
|
|
description: 'Full node type with prefix',
|
|
required: true
|
|
}
|
|
},
|
|
returns: 'Essential properties with examples',
|
|
examples: ['get_node_essentials("nodes-base.httpRequest")'],
|
|
useCases: ['Quick configuration', 'Property discovery'],
|
|
performance: 'Fast - pre-filtered data',
|
|
bestPractices: ['Always try essentials first'],
|
|
pitfalls: ['May not include all advanced options'],
|
|
relatedTools: ['get_node_info']
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
|
|
// No need to mock package.json - let the actual module read it
|
|
|
|
describe('tools-documentation', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('getToolDocumentation', () => {
|
|
describe('essentials mode', () => {
|
|
it('should return essential documentation for existing tool', () => {
|
|
const doc = getToolDocumentation('search_nodes', 'essentials');
|
|
|
|
expect(doc).toContain('# search_nodes');
|
|
expect(doc).toContain('Search nodes by keywords');
|
|
expect(doc).toContain('**Example**: search_nodes({query: "slack"})');
|
|
expect(doc).toContain('**Key parameters**: query, mode, limit');
|
|
expect(doc).toContain('**Performance**: Instant (<10ms)');
|
|
expect(doc).toContain('- Use single words for precision');
|
|
expect(doc).toContain('- Try FUZZY mode for typos');
|
|
expect(doc).toContain('For full documentation, use: tools_documentation({topic: "search_nodes", depth: "full"})');
|
|
});
|
|
|
|
it('should return error message for unknown tool', () => {
|
|
const doc = getToolDocumentation('unknown_tool', 'essentials');
|
|
expect(doc).toBe("Tool 'unknown_tool' not found. Use tools_documentation() to see available tools.");
|
|
});
|
|
|
|
it('should use essentials as default depth', () => {
|
|
const docDefault = getToolDocumentation('search_nodes');
|
|
const docEssentials = getToolDocumentation('search_nodes', 'essentials');
|
|
expect(docDefault).toBe(docEssentials);
|
|
});
|
|
});
|
|
|
|
describe('full mode', () => {
|
|
it('should return complete documentation for existing tool', () => {
|
|
const doc = getToolDocumentation('search_nodes', 'full');
|
|
|
|
expect(doc).toContain('# search_nodes');
|
|
expect(doc).toContain('Full-text search across all n8n nodes');
|
|
expect(doc).toContain('## Parameters');
|
|
expect(doc).toContain('- **query** (string, required): Search terms');
|
|
expect(doc).toContain('- **mode** (string): Search mode');
|
|
expect(doc).toContain('- **limit** (number): Max results');
|
|
expect(doc).toContain('## Returns');
|
|
expect(doc).toContain('Array of matching nodes with metadata');
|
|
expect(doc).toContain('## Examples');
|
|
expect(doc).toContain('search_nodes({query: "webhook"})');
|
|
expect(doc).toContain('## Common Use Cases');
|
|
expect(doc).toContain('- Finding integration nodes');
|
|
expect(doc).toContain('## Performance');
|
|
expect(doc).toContain('Instant - uses in-memory index');
|
|
expect(doc).toContain('## Best Practices');
|
|
expect(doc).toContain('- Start with single words');
|
|
expect(doc).toContain('## Common Pitfalls');
|
|
expect(doc).toContain('- Overly specific queries');
|
|
expect(doc).toContain('## Related Tools');
|
|
expect(doc).toContain('- get_node');
|
|
});
|
|
});
|
|
|
|
describe('special documentation topics', () => {
|
|
it('should return JavaScript Code node guide for javascript_code_node_guide', () => {
|
|
const doc = getToolDocumentation('javascript_code_node_guide', 'essentials');
|
|
expect(doc).toContain('# JavaScript Code Node Guide');
|
|
expect(doc).toContain('$input.all()');
|
|
expect(doc).toContain('DateTime');
|
|
});
|
|
|
|
it('should return Python Code node guide for python_code_node_guide', () => {
|
|
const doc = getToolDocumentation('python_code_node_guide', 'essentials');
|
|
expect(doc).toContain('# Python Code Node Guide');
|
|
expect(doc).toContain('_input.all()');
|
|
expect(doc).toContain('_json');
|
|
});
|
|
|
|
it('should return full JavaScript guide when requested', () => {
|
|
const doc = getToolDocumentation('javascript_code_node_guide', 'full');
|
|
expect(doc).toContain('# JavaScript Code Node Complete Guide');
|
|
expect(doc).toContain('## Data Access Patterns');
|
|
expect(doc).toContain('## Available Built-in Functions');
|
|
expect(doc).toContain('$helpers.httpRequest');
|
|
});
|
|
|
|
it('should return full Python guide when requested', () => {
|
|
const doc = getToolDocumentation('python_code_node_guide', 'full');
|
|
expect(doc).toContain('# Python Code Node Complete Guide');
|
|
expect(doc).toContain('## Available Built-in Modules');
|
|
expect(doc).toContain('## Limitations & Workarounds');
|
|
expect(doc).toContain('import json');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getToolsOverview', () => {
|
|
describe('essentials mode', () => {
|
|
it('should return essential overview with categories', () => {
|
|
const overview = getToolsOverview('essentials');
|
|
|
|
expect(overview).toContain('# n8n MCP Tools Reference');
|
|
expect(overview).toContain('## Important: Compatibility Notice');
|
|
// The tools-documentation module dynamically reads version from package.json
|
|
// so we need to read it the same way to match
|
|
const packageJson = require('../../../package.json');
|
|
const n8nVersion = packageJson.dependencies.n8n.replace(/[^0-9.]/g, '');
|
|
expect(overview).toContain(`n8n version ${n8nVersion}`);
|
|
expect(overview).toContain('## Code Node Configuration');
|
|
expect(overview).toContain('## Standard Workflow Pattern');
|
|
expect(overview).toContain('**Discovery Tools**');
|
|
expect(overview).toContain('**Configuration Tools**');
|
|
expect(overview).toContain('**Validation Tools**');
|
|
expect(overview).toContain('## Performance Characteristics');
|
|
expect(overview).toContain('- Instant (<10ms)');
|
|
expect(overview).toContain('tools_documentation({topic: "tool_name", depth: "full"})');
|
|
});
|
|
|
|
it('should use essentials as default', () => {
|
|
const overviewDefault = getToolsOverview();
|
|
const overviewEssentials = getToolsOverview('essentials');
|
|
expect(overviewDefault).toBe(overviewEssentials);
|
|
});
|
|
});
|
|
|
|
describe('full mode', () => {
|
|
it('should return complete overview with all tools', () => {
|
|
const overview = getToolsOverview('full');
|
|
|
|
expect(overview).toContain('# n8n MCP Tools - Complete Reference');
|
|
expect(overview).toContain('## All Available Tools by Category');
|
|
expect(overview).toContain('### Discovery');
|
|
expect(overview).toContain('- **search_nodes**: Search nodes by keywords');
|
|
expect(overview).toContain('### Validation');
|
|
expect(overview).toContain('- **validate_workflow**: Validate complete workflow structure');
|
|
expect(overview).toContain('## Usage Notes');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('searchToolDocumentation', () => {
|
|
it('should find tools matching keyword in name', () => {
|
|
const results = searchToolDocumentation('search');
|
|
expect(results).toContain('search_nodes');
|
|
});
|
|
|
|
it('should find tools matching keyword in description', () => {
|
|
const results = searchToolDocumentation('workflow');
|
|
expect(results).toContain('validate_workflow');
|
|
});
|
|
|
|
it('should be case insensitive', () => {
|
|
const resultsLower = searchToolDocumentation('search');
|
|
const resultsUpper = searchToolDocumentation('SEARCH');
|
|
expect(resultsLower).toEqual(resultsUpper);
|
|
});
|
|
|
|
it('should return empty array for no matches', () => {
|
|
const results = searchToolDocumentation('nonexistentxyz123');
|
|
expect(results).toEqual([]);
|
|
});
|
|
|
|
it('should search in both essentials and full descriptions', () => {
|
|
const results = searchToolDocumentation('validation');
|
|
expect(results.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('getToolsByCategory', () => {
|
|
it('should return tools for discovery category', () => {
|
|
const tools = getToolsByCategory('discovery');
|
|
expect(tools).toContain('search_nodes');
|
|
});
|
|
|
|
it('should return tools for validation category', () => {
|
|
const tools = getToolsByCategory('validation');
|
|
expect(tools).toContain('validate_workflow');
|
|
});
|
|
|
|
it('should return tools for configuration category', () => {
|
|
const tools = getToolsByCategory('configuration');
|
|
expect(tools).toContain('get_node_essentials');
|
|
});
|
|
|
|
it('should return empty array for unknown category', () => {
|
|
const tools = getToolsByCategory('unknown_category');
|
|
expect(tools).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('getAllCategories', () => {
|
|
it('should return all unique categories', () => {
|
|
const categories = getAllCategories();
|
|
expect(categories).toContain('discovery');
|
|
expect(categories).toContain('validation');
|
|
expect(categories).toContain('configuration');
|
|
});
|
|
|
|
it('should not have duplicates', () => {
|
|
const categories = getAllCategories();
|
|
const uniqueCategories = new Set(categories);
|
|
expect(categories.length).toBe(uniqueCategories.size);
|
|
});
|
|
|
|
it('should return non-empty array', () => {
|
|
const categories = getAllCategories();
|
|
expect(categories.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
it('should handle missing tool gracefully', () => {
|
|
const doc = getToolDocumentation('missing_tool');
|
|
expect(doc).toContain("Tool 'missing_tool' not found");
|
|
expect(doc).toContain('Use tools_documentation()');
|
|
});
|
|
|
|
it('should handle empty search query', () => {
|
|
const results = searchToolDocumentation('');
|
|
// Should match all tools since empty string is in everything
|
|
expect(results.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Documentation Quality', () => {
|
|
it('should format parameters correctly in full mode', () => {
|
|
const doc = getToolDocumentation('search_nodes', 'full');
|
|
|
|
// Check parameter formatting
|
|
expect(doc).toMatch(/- \*\*query\*\* \(string, required\): Search terms/);
|
|
expect(doc).toMatch(/- \*\*mode\*\* \(string\): Search mode/);
|
|
expect(doc).toMatch(/- \*\*limit\*\* \(number\): Max results/);
|
|
});
|
|
|
|
it('should include code blocks for examples', () => {
|
|
const doc = getToolDocumentation('search_nodes', 'full');
|
|
expect(doc).toContain('```javascript');
|
|
expect(doc).toContain('```');
|
|
});
|
|
|
|
it('should have consistent section headers', () => {
|
|
const doc = getToolDocumentation('search_nodes', 'full');
|
|
const expectedSections = [
|
|
'## Parameters',
|
|
'## Returns',
|
|
'## Examples',
|
|
'## Common Use Cases',
|
|
'## Performance',
|
|
'## Best Practices',
|
|
'## Common Pitfalls',
|
|
'## Related Tools'
|
|
];
|
|
|
|
expectedSections.forEach(section => {
|
|
expect(doc).toContain(section);
|
|
});
|
|
});
|
|
});
|
|
}); |