mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-09 23:03:12 +00:00
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:
87
src/loaders/node-loader.ts
Normal file
87
src/loaders/node-loader.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import path from 'path';
|
||||
|
||||
export interface LoadedNode {
|
||||
packageName: string;
|
||||
nodeName: string;
|
||||
NodeClass: any;
|
||||
}
|
||||
|
||||
export class N8nNodeLoader {
|
||||
private readonly CORE_PACKAGES = [
|
||||
'n8n-nodes-base',
|
||||
'@n8n/n8n-nodes-langchain'
|
||||
];
|
||||
|
||||
async loadAllNodes(): Promise<LoadedNode[]> {
|
||||
const results: LoadedNode[] = [];
|
||||
|
||||
for (const pkg of this.CORE_PACKAGES) {
|
||||
try {
|
||||
console.log(`\n📦 Loading package: ${pkg}`);
|
||||
// Direct require - no complex path resolution
|
||||
const packageJson = require(`${pkg}/package.json`);
|
||||
console.log(` Found ${Object.keys(packageJson.n8n?.nodes || {}).length} nodes in package.json`);
|
||||
const nodes = await this.loadPackageNodes(pkg, packageJson);
|
||||
results.push(...nodes);
|
||||
} catch (error) {
|
||||
console.error(`Failed to load ${pkg}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private async loadPackageNodes(packageName: string, packageJson: any): Promise<LoadedNode[]> {
|
||||
const n8nConfig = packageJson.n8n || {};
|
||||
const nodes: LoadedNode[] = [];
|
||||
|
||||
// Check if nodes is an array or object
|
||||
const nodesList = n8nConfig.nodes || [];
|
||||
|
||||
if (Array.isArray(nodesList)) {
|
||||
// Handle array format (n8n-nodes-base uses this)
|
||||
for (const nodePath of nodesList) {
|
||||
try {
|
||||
const fullPath = require.resolve(`${packageName}/${nodePath}`);
|
||||
const nodeModule = require(fullPath);
|
||||
|
||||
// Extract node name from path (e.g., "dist/nodes/Slack/Slack.node.js" -> "Slack")
|
||||
const nodeNameMatch = nodePath.match(/\/([^\/]+)\.node\.(js|ts)$/);
|
||||
const nodeName = nodeNameMatch ? nodeNameMatch[1] : path.basename(nodePath, '.node.js');
|
||||
|
||||
// Handle default export and various export patterns
|
||||
const NodeClass = nodeModule.default || nodeModule[nodeName] || Object.values(nodeModule)[0];
|
||||
if (NodeClass) {
|
||||
nodes.push({ packageName, nodeName, NodeClass });
|
||||
console.log(` ✓ Loaded ${nodeName} from ${packageName}`);
|
||||
} else {
|
||||
console.warn(` ⚠ No valid export found for ${nodeName} in ${packageName}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(` ✗ Failed to load node from ${packageName}/${nodePath}:`, (error as Error).message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle object format (for other packages)
|
||||
for (const [nodeName, nodePath] of Object.entries(nodesList)) {
|
||||
try {
|
||||
const fullPath = require.resolve(`${packageName}/${nodePath as string}`);
|
||||
const nodeModule = require(fullPath);
|
||||
|
||||
// Handle default export and various export patterns
|
||||
const NodeClass = nodeModule.default || nodeModule[nodeName] || Object.values(nodeModule)[0];
|
||||
if (NodeClass) {
|
||||
nodes.push({ packageName, nodeName, NodeClass });
|
||||
console.log(` ✓ Loaded ${nodeName} from ${packageName}`);
|
||||
} else {
|
||||
console.warn(` ⚠ No valid export found for ${nodeName} in ${packageName}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(` ✗ Failed to load node ${nodeName} from ${packageName}:`, (error as Error).message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user