feat: Implement n8n-MCP Enhancement Plan v2.1 Final

- Implement simple node loader supporting n8n-nodes-base and langchain packages
- Create parser handling declarative, programmatic, and versioned nodes
- Build documentation mapper with 89% coverage (405/457 nodes)
- Setup SQLite database with minimal schema
- Create rebuild script for one-command database updates
- Implement validation script for critical nodes
- Update MCP server with documentation-focused tools
- Add npm scripts for streamlined workflow

Successfully loads 457/458 nodes with accurate documentation mapping.
Versioned node detection working (46 nodes detected).
3/4 critical nodes pass validation tests.

Known limitations:
- Slack operations extraction incomplete for some versioned nodes
- One langchain node fails due to missing dependency
- No AI tools detected (none have usableAsTool flag)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-06-12 14:18:19 +02:00
parent b50025081a
commit 8bf670c31e
21 changed files with 9206 additions and 790 deletions

View File

@@ -0,0 +1,63 @@
import { promises as fs } from 'fs';
import path from 'path';
export class DocsMapper {
private docsPath = path.join(process.cwd(), 'n8n-docs');
// Known documentation mapping fixes
private readonly KNOWN_FIXES: Record<string, string> = {
'httpRequest': 'httprequest',
'code': 'code',
'webhook': 'webhook',
'respondToWebhook': 'respondtowebhook',
// With package prefix
'n8n-nodes-base.httpRequest': 'httprequest',
'n8n-nodes-base.code': 'code',
'n8n-nodes-base.webhook': 'webhook',
'n8n-nodes-base.respondToWebhook': 'respondtowebhook'
};
async fetchDocumentation(nodeType: string): Promise<string | null> {
// Apply known fixes first
const fixedType = this.KNOWN_FIXES[nodeType] || nodeType;
// Extract node name
const nodeName = fixedType.split('.').pop()?.toLowerCase();
if (!nodeName) {
console.log(`⚠️ Could not extract node name from: ${nodeType}`);
return null;
}
console.log(`📄 Looking for docs for: ${nodeType} -> ${nodeName}`);
// Try different documentation paths - both files and directories
const possiblePaths = [
// Direct file paths
`docs/integrations/builtin/core-nodes/n8n-nodes-base.${nodeName}.md`,
`docs/integrations/builtin/app-nodes/n8n-nodes-base.${nodeName}.md`,
`docs/integrations/builtin/trigger-nodes/n8n-nodes-base.${nodeName}.md`,
`docs/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.${nodeName}.md`,
// Directory with index.md
`docs/integrations/builtin/core-nodes/n8n-nodes-base.${nodeName}/index.md`,
`docs/integrations/builtin/app-nodes/n8n-nodes-base.${nodeName}/index.md`,
`docs/integrations/builtin/trigger-nodes/n8n-nodes-base.${nodeName}/index.md`,
`docs/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.${nodeName}/index.md`
];
// Try each path
for (const relativePath of possiblePaths) {
try {
const fullPath = path.join(this.docsPath, relativePath);
const content = await fs.readFile(fullPath, 'utf-8');
console.log(` ✓ Found docs at: ${relativePath}`);
return content;
} catch (error) {
// File doesn't exist, try next
continue;
}
}
console.log(` ✗ No docs found for ${nodeName}`);
return null;
}
}