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:
212
src/scripts/test-ai-workflow-validation.ts
Normal file
212
src/scripts/test-ai-workflow-validation.ts
Normal 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);
|
||||
}
|
||||
54
src/scripts/test-mcp-tools.ts
Normal file
54
src/scripts/test-mcp-tools.ts
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user