feat: enhance AI tool support and clarify documentation (v2.5.1)

- Update tool descriptions to clarify ANY node can be used as AI tool
- Add get_node_as_tool_info to available tools in README
- Enhance workflow validation tool descriptions for AI connections
- Update README with v2.5.1 release notes
- Remove redundant _General__Scrape_with_HTTP_tool.json file
- Bump version to 2.5.1 in package.json

The key insight: ANY n8n node can be connected to an AI Agent's tool
port, not just those marked with usableAsTool=true. This update makes
that clear throughout the documentation and tool descriptions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-06-24 15:52:01 +02:00
parent 533b1acc20
commit aad1b69fb1
10 changed files with 737 additions and 146 deletions

View File

@@ -0,0 +1,212 @@
#!/usr/bin/env node
/**
* Test AI workflow validation enhancements
*/
import { createDatabaseAdapter } from '../database/database-adapter';
import { NodeRepository } from '../database/node-repository';
import { WorkflowValidator } from '../services/workflow-validator';
import { Logger } from '../utils/logger';
import { EnhancedConfigValidator } from '../services/enhanced-config-validator';
const logger = new Logger({ prefix: '[TestAIWorkflow]' });
// Test workflow with AI Agent and tools
const aiWorkflow = {
name: 'AI Agent with Tools',
nodes: [
{
id: '1',
name: 'Webhook',
type: 'n8n-nodes-base.webhook',
position: [100, 100],
parameters: {
path: 'ai-webhook',
httpMethod: 'POST'
}
},
{
id: '2',
name: 'AI Agent',
type: '@n8n/n8n-nodes-langchain.agent',
position: [300, 100],
parameters: {
text: '={{ $json.query }}',
systemMessage: 'You are a helpful assistant with access to tools'
}
},
{
id: '3',
name: 'Google Sheets Tool',
type: 'n8n-nodes-base.googleSheets',
position: [300, 250],
parameters: {
operation: 'append',
sheetId: '={{ $fromAI("sheetId", "Sheet ID") }}',
range: 'A:Z'
}
},
{
id: '4',
name: 'Slack Tool',
type: 'n8n-nodes-base.slack',
position: [300, 350],
parameters: {
resource: 'message',
operation: 'post',
channel: '={{ $fromAI("channel", "Channel name") }}',
text: '={{ $fromAI("message", "Message text") }}'
}
},
{
id: '5',
name: 'Response',
type: 'n8n-nodes-base.respondToWebhook',
position: [500, 100],
parameters: {
responseCode: 200
}
}
],
connections: {
'Webhook': {
main: [[{ node: 'AI Agent', type: 'main', index: 0 }]]
},
'AI Agent': {
main: [[{ node: 'Response', type: 'main', index: 0 }]],
ai_tool: [
[
{ node: 'Google Sheets Tool', type: 'ai_tool', index: 0 },
{ node: 'Slack Tool', type: 'ai_tool', index: 0 }
]
]
}
}
};
// Test workflow without tools (should trigger warning)
const aiWorkflowNoTools = {
name: 'AI Agent without Tools',
nodes: [
{
id: '1',
name: 'Manual',
type: 'n8n-nodes-base.manualTrigger',
position: [100, 100],
parameters: {}
},
{
id: '2',
name: 'AI Agent',
type: '@n8n/n8n-nodes-langchain.agent',
position: [300, 100],
parameters: {
text: 'Hello AI'
}
}
],
connections: {
'Manual': {
main: [[{ node: 'AI Agent', type: 'main', index: 0 }]]
}
}
};
// Test workflow with googleSheetsTool (unknown node type)
const unknownToolWorkflow = {
name: 'Unknown Tool Test',
nodes: [
{
id: '1',
name: 'Agent',
type: 'nodes-langchain.agent',
position: [100, 100],
parameters: {}
},
{
id: '2',
name: 'Sheets Tool',
type: 'googleSheetsTool',
position: [300, 100],
parameters: {}
}
],
connections: {
'Agent': {
ai_tool: [[{ node: 'Sheets Tool', type: 'ai_tool', index: 0 }]]
}
}
};
async function testWorkflow(name: string, workflow: any) {
console.log(`\n🧪 Testing: ${name}`);
console.log('='.repeat(50));
const db = await createDatabaseAdapter('./data/nodes.db');
const repository = new NodeRepository(db);
const validator = new WorkflowValidator(repository, EnhancedConfigValidator);
try {
const result = await validator.validateWorkflow(workflow);
console.log(`\n📊 Validation Results:`);
console.log(`Valid: ${result.valid ? '✅' : '❌'}`);
if (result.errors.length > 0) {
console.log('\n❌ Errors:');
result.errors.forEach((err: any) => {
if (typeof err === 'string') {
console.log(` - ${err}`);
} else if (err.message) {
const nodeInfo = err.nodeName ? ` [${err.nodeName}]` : '';
console.log(` - ${err.message}${nodeInfo}`);
} else {
console.log(` - ${JSON.stringify(err, null, 2)}`);
}
});
}
if (result.warnings.length > 0) {
console.log('\n⚠ Warnings:');
result.warnings.forEach((warn: any) => {
const msg = warn.message || warn;
const nodeInfo = warn.nodeName ? ` [${warn.nodeName}]` : '';
console.log(` - ${msg}${nodeInfo}`);
});
}
if (result.suggestions.length > 0) {
console.log('\n💡 Suggestions:');
result.suggestions.forEach((sug: any) => console.log(` - ${sug}`));
}
console.log('\n📈 Statistics:');
console.log(` - Total nodes: ${result.statistics.totalNodes}`);
console.log(` - Valid connections: ${result.statistics.validConnections}`);
console.log(` - Invalid connections: ${result.statistics.invalidConnections}`);
console.log(` - Expressions validated: ${result.statistics.expressionsValidated}`);
} catch (error) {
console.error('Validation error:', error);
} finally {
db.close();
}
}
async function main() {
console.log('🤖 Testing AI Workflow Validation Enhancements');
// Test 1: Complete AI workflow with tools
await testWorkflow('AI Agent with Multiple Tools', aiWorkflow);
// Test 2: AI Agent without tools (should warn)
await testWorkflow('AI Agent without Tools', aiWorkflowNoTools);
// Test 3: Unknown tool type (like googleSheetsTool)
await testWorkflow('Unknown Tool Type', unknownToolWorkflow);
console.log('\n✅ All tests completed!');
}
if (require.main === module) {
main().catch(console.error);
}

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env node
/**
* Test MCP tools directly
*/
import { createDatabaseAdapter } from '../database/database-adapter';
import { NodeRepository } from '../database/node-repository';
import { N8NDocumentationMCPServer } from '../mcp/server-update';
import { Logger } from '../utils/logger';
const logger = new Logger({ prefix: '[TestMCPTools]' });
async function testTool(server: any, toolName: string, args: any) {
try {
console.log(`\n🔧 Testing: ${toolName}`);
console.log('Args:', JSON.stringify(args, null, 2));
console.log('-'.repeat(60));
const result = await server[toolName].call(server, args);
console.log('Result:', JSON.stringify(result, null, 2));
} catch (error) {
console.error(`❌ Error: ${error}`);
}
}
async function main() {
console.log('🤖 Testing MCP Tools\n');
// Create server instance and wait for initialization
const server = new N8NDocumentationMCPServer();
// Give it time to initialize
await new Promise(resolve => setTimeout(resolve, 100));
// Test get_node_as_tool_info
console.log('\n=== Testing get_node_as_tool_info ===');
await testTool(server, 'getNodeAsToolInfo', 'nodes-base.slack');
await testTool(server, 'getNodeAsToolInfo', 'nodes-base.googleSheets');
// Test enhanced get_node_info with aiToolCapabilities
console.log('\n\n=== Testing get_node_info (with aiToolCapabilities) ===');
await testTool(server, 'getNodeInfo', 'nodes-base.httpRequest');
// Test list_ai_tools with enhanced response
console.log('\n\n=== Testing list_ai_tools (enhanced) ===');
await testTool(server, 'listAITools', {});
console.log('\n✅ All tests completed!');
process.exit(0);
}
if (require.main === module) {
main().catch(console.error);
}