diff --git a/CHANGELOG.md b/CHANGELOG.md index d7239d2..6495c16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.32.1] - 2026-01-08 + +### Fixed + +- **Community node case sensitivity bug**: Fixed `extractNodeNameFromPackage` to use lowercase node names, matching n8n's community node convention (e.g., `chatwoot` instead of `Chatwoot`). This resolves validation failures for community nodes with incorrect casing. +- **Case-insensitive node lookup**: Added fallback in `getNode` to handle case differences between stored and requested node types for better robustness. + ## [2.32.0] - 2026-01-07 ### Added diff --git a/data/nodes.db b/data/nodes.db index 1ba6242..ec78909 100644 Binary files a/data/nodes.db and b/data/nodes.db differ diff --git a/package.json b/package.json index 427a123..ea7f234 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "n8n-mcp", - "version": "2.32.0", + "version": "2.32.1", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/community/community-node-service.ts b/src/community/community-node-service.ts index a7a21c7..1d01de3 100644 --- a/src/community/community-node-service.ts +++ b/src/community/community-node-service.ts @@ -355,9 +355,13 @@ export class CommunityNodeService { } /** - * Extract a readable node name from npm package name. - * e.g., "n8n-nodes-globals" -> "Globals" - * e.g., "@company/n8n-nodes-mynode" -> "Mynode" + * Extract node name from npm package name. + * n8n community nodes typically use lowercase node class names. + * e.g., "n8n-nodes-chatwoot" -> "chatwoot" + * e.g., "@company/n8n-nodes-mynode" -> "mynode" + * + * Note: We use lowercase because most community nodes follow this convention. + * Verified nodes from Strapi have the correct casing in nodeDesc.name. */ private extractNodeNameFromPackage(packageName: string): string { // Remove scope if present @@ -366,11 +370,9 @@ export class CommunityNodeService { // Remove n8n-nodes- prefix name = name.replace(/^n8n-nodes-/, ''); - // Capitalize first letter of each word - return name - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(''); + // Remove hyphens and keep lowercase (n8n community node convention) + // e.g., "bright-data" -> "brightdata", "chatwoot" -> "chatwoot" + return name.replace(/-/g, '').toLowerCase(); } /** diff --git a/src/database/node-repository.ts b/src/database/node-repository.ts index 96b56a9..6373f6a 100644 --- a/src/database/node-repository.ts +++ b/src/database/node-repository.ts @@ -103,6 +103,18 @@ export class NodeRepository { } } + // Fallback: case-insensitive lookup for community nodes + // Handles cases where node type casing differs (e.g., .Chatwoot vs .chatwoot) + if (!row) { + const caseInsensitiveRow = this.db.prepare(` + SELECT * FROM nodes WHERE LOWER(node_type) = LOWER(?) + `).get(nodeType) as any; + + if (caseInsensitiveRow) { + return this.parseNodeRow(caseInsensitiveRow); + } + } + if (!row) return null; return this.parseNodeRow(row); diff --git a/tests/unit/community/community-node-service.test.ts b/tests/unit/community/community-node-service.test.ts index 91a26f2..c2b8b74 100644 --- a/tests/unit/community/community-node-service.test.ts +++ b/tests/unit/community/community-node-service.test.ts @@ -519,9 +519,9 @@ describe('CommunityNodeService', () => { expect(mockRepository.saveNode).toHaveBeenCalledWith( expect.objectContaining({ - nodeType: 'n8n-nodes-npm-test.NpmTest', + nodeType: 'n8n-nodes-npm-test.npmtest', packageName: 'n8n-nodes-npm-test', - displayName: 'NpmTest', + displayName: 'npmtest', description: 'A test npm community node', isCommunity: true, isVerified: false, @@ -546,7 +546,7 @@ describe('CommunityNodeService', () => { expect(mockRepository.saveNode).toHaveBeenCalledWith( expect.objectContaining({ - displayName: 'Custom', + displayName: 'custom', }) ); });