Compare commits

..

1 Commits

Author SHA1 Message Date
czlonkowski
e583261d37 fix: Add missing tslib dependency to fix npx installation failures (#342)
Fixed critical dependency issue where tslib was missing from the published
npm package, causing MODULE_NOT_FOUND errors when users ran
'npx n8n-mcp@latest' on Windows and other platforms.

Root Cause:
- @supabase/functions-js requires tslib at runtime
- tslib was NOT in package.runtime.json dependencies
- CI/CD copies package.runtime.json → package.json before publishing
- Result: Published package had no tslib → npx installations failed

Changes:
- Added tslib@^2.6.2 to package.runtime.json (critical fix)
- Added tslib@^2.6.2 to package.json (development consistency)
- Updated package.runtime.json version to 2.20.6
- Updated package.json version to 2.20.6
- Added comprehensive CHANGELOG.md entry

Impact:
-  npx n8n-mcp@latest now works on all platforms
-  No breaking changes (tslib already in transitive tree)
-  Fixes 100% failure rate for fresh npx installations

Fixes #342

Conceived by Romuald Członkowski - www.aiadvisors.pl/en
2025-10-21 23:16:30 +02:00
10 changed files with 2954 additions and 3198 deletions

View File

@@ -7,96 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [2.20.7] - 2025-10-22
### 🔄 Dependencies
**Updated n8n to v1.116.2**
Updated all n8n dependencies to the latest compatible versions:
- `n8n`: 1.115.2 → 1.116.2
- `n8n-core`: 1.114.0 → 1.115.1
- `n8n-workflow`: 1.112.0 → 1.113.0
- `@n8n/n8n-nodes-langchain`: 1.114.1 → 1.115.1
**Database Rebuild:**
- Rebuilt node database with 542 nodes from updated n8n packages
- All 542 nodes loaded successfully from both n8n-nodes-base (439 nodes) and @n8n/n8n-nodes-langchain (103 nodes)
- Documentation mapping completed for all nodes
**Testing:**
- Changes validated in CI/CD pipeline with full test suite (705 tests)
- Critical nodes validated: httpRequest, code, slack, agent
### 🐛 Bug Fixes
**FTS5 Search Ranking - Exact Match Prioritization**
Fixed critical bug in production search where exact matches weren't appearing first in search results.
#### Problem
- SQL ORDER BY clause was `ORDER BY rank, CASE ... END` (wrong order)
- FTS5 rank sorted first, CASE statement only acted as tiebreaker
- Since FTS5 ranks are always unique, CASE boosting never applied
- Additionally, CASE used case-sensitive comparison failing to match nodes like "Webhook" when searching "webhook"
- Result: Searching "webhook" returned "Webflow Trigger" first, actual "Webhook" node ranked 4th
#### Root Cause Analysis
**SQL Ordering Issue:**
```sql
-- BEFORE (Broken):
ORDER BY rank, CASE ... END -- rank first, CASE never used
-- Result: webhook ranks 4th (-9.64 rank)
-- Top 3: webflowTrigger (-10.20), vonage (-10.09), renameKeys (-10.01)
-- AFTER (Fixed):
ORDER BY CASE ... END, rank -- CASE first, exact matches prioritized
-- Result: webhook ranks 1st (CASE priority 0)
```
**Case-Sensitivity Issue:**
- Old: `WHEN n.display_name = ?` (case-sensitive, fails on "Webhook" vs "webhook")
- New: `WHEN LOWER(n.display_name) = LOWER(?)` (case-insensitive, matches correctly)
#### Fixed
**1. Production Code** (`src/mcp/server.ts` lines 1278-1295)
- Changed ORDER BY from: `rank, CASE ... END`
- To: `CASE WHEN LOWER(n.display_name) = LOWER(?) ... END, rank`
- Added case-insensitive comparison with LOWER() function
- Exact matches now consistently appear first in search results
**2. Test Files Updated**
- `tests/integration/database/node-fts5-search.test.ts` (lines 137-160)
- `tests/integration/ci/database-population.test.ts` (lines 206-234)
- Both updated to match corrected SQL logic with case-insensitive comparison
- Tests now accurately validate production search behavior
#### Impact
**Search Quality:**
- ✅ Exact matches now always rank first (webhook, http, code, etc.)
- ✅ Case-insensitive matching works correctly (Webhook = webhook = WEBHOOK)
- ✅ Better user experience - predictable search results
- ✅ SQL query more efficient (correct ordering at database level)
**Performance:**
- Same or better performance (less JavaScript sorting needed)
- Database does the heavy lifting with correct ORDER BY
- JavaScript sorting still provides additional relevance refinement
**Testing:**
- All 705 tests passing (703 passed + 2 fixed)
- Comprehensive testing by n8n-mcp-tester agent
- Code review approved with minor optimization suggestions for future
**Verified Search Results:**
- "webhook" → nodes-base.webhook (1st)
- "http" → nodes-base.httpRequest (1st)
- "code" → nodes-base.code (1st)
- "slack" → nodes-base.slack (1st)
- All case variations work correctly (WEBHOOK, Webhook, webhook)
## [2.20.6] - 2025-10-21
### 🐛 Bug Fixes

View File

@@ -192,5 +192,4 @@ NEVER proactively create documentation files (*.md) or README files. Only create
- When the user asks to review issues, you should use GH CLI to get the issue and all the comments
- When the task can be divided into separated subtasks, you should spawn separate sub-agents to handle them in paralel
- Use the best sub-agent for the task as per their descriptions
- Do not use hyperbolic or dramatic language in comments and documentation
- Add to every commit and PR: Concieved by Romuald Członkowski - and then link to www.aiadvisors.pl/en. Don't add it in conversations
- Do not use hyperbolic or dramatic language in comments and documentation

View File

@@ -5,7 +5,7 @@
[![npm version](https://img.shields.io/npm/v/n8n-mcp.svg)](https://www.npmjs.com/package/n8n-mcp)
[![codecov](https://codecov.io/gh/czlonkowski/n8n-mcp/graph/badge.svg?token=YOUR_TOKEN)](https://codecov.io/gh/czlonkowski/n8n-mcp)
[![Tests](https://img.shields.io/badge/tests-3336%20passing-brightgreen.svg)](https://github.com/czlonkowski/n8n-mcp/actions)
[![n8n version](https://img.shields.io/badge/n8n-^1.116.2-orange.svg)](https://github.com/n8n-io/n8n)
[![n8n version](https://img.shields.io/badge/n8n-^1.115.2-orange.svg)](https://github.com/n8n-io/n8n)
[![Docker](https://img.shields.io/badge/docker-ghcr.io%2Fczlonkowski%2Fn8n--mcp-green.svg)](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)

Binary file not shown.

5997
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp",
"version": "2.20.7",
"version": "2.20.6",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -140,15 +140,15 @@
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.20.1",
"@n8n/n8n-nodes-langchain": "^1.115.1",
"@n8n/n8n-nodes-langchain": "^1.114.1",
"@supabase/supabase-js": "^2.57.4",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"express-rate-limit": "^7.1.5",
"lru-cache": "^11.2.1",
"n8n": "^1.116.2",
"n8n-core": "^1.115.1",
"n8n-workflow": "^1.113.0",
"n8n": "^1.115.2",
"n8n-core": "^1.114.0",
"n8n-workflow": "^1.112.0",
"openai": "^4.77.0",
"sql.js": "^1.13.0",
"tslib": "^2.6.2",

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp-runtime",
"version": "2.20.7",
"version": "2.20.6",
"description": "n8n MCP Server Runtime Dependencies Only",
"private": true,
"dependencies": {

View File

@@ -1276,20 +1276,20 @@ export class N8NDocumentationMCPServer {
try {
// Use FTS5 with ranking
const nodes = this.db.prepare(`
SELECT
SELECT
n.*,
rank
FROM nodes n
JOIN nodes_fts ON n.rowid = nodes_fts.rowid
WHERE nodes_fts MATCH ?
ORDER BY
CASE
WHEN LOWER(n.display_name) = LOWER(?) THEN 0
WHEN LOWER(n.display_name) LIKE LOWER(?) THEN 1
WHEN LOWER(n.node_type) LIKE LOWER(?) THEN 2
ORDER BY
rank,
CASE
WHEN n.display_name = ? THEN 0
WHEN n.display_name LIKE ? THEN 1
WHEN n.node_type LIKE ? THEN 2
ELSE 3
END,
rank,
n.display_name
LIMIT ?
`).all(ftsQuery, cleanedQuery, `%${cleanedQuery}%`, `%${cleanedQuery}%`, limit) as (NodeRow & { rank: number })[];

View File

@@ -205,20 +205,9 @@ describe.skipIf(!dbExists)('Database Content Validation', () => {
it('MUST have FTS5 index properly ranked', () => {
const results = db.prepare(`
SELECT
n.node_type,
rank
FROM nodes n
JOIN nodes_fts ON n.rowid = nodes_fts.rowid
SELECT node_type, rank FROM nodes_fts
WHERE nodes_fts MATCH 'webhook'
ORDER BY
CASE
WHEN LOWER(n.display_name) = LOWER('webhook') THEN 0
WHEN LOWER(n.display_name) LIKE LOWER('%webhook%') THEN 1
WHEN LOWER(n.node_type) LIKE LOWER('%webhook%') THEN 2
ELSE 3
END,
rank
ORDER BY rank
LIMIT 5
`).all();
@@ -226,7 +215,7 @@ describe.skipIf(!dbExists)('Database Content Validation', () => {
'CRITICAL: FTS5 ranking not working. Search quality will be degraded.'
).toBeGreaterThan(0);
// Exact match should be in top results (using production boosting logic with CASE-first ordering)
// Exact match should be in top results
const topNodes = results.slice(0, 3).map((r: any) => r.node_type);
expect(topNodes,
'WARNING: Exact match "nodes-base.webhook" not in top 3 ranked results'

View File

@@ -136,25 +136,14 @@ describe('Node FTS5 Search Integration Tests', () => {
describe('FTS5 Search Quality', () => {
it('should rank exact matches higher', () => {
const results = db.prepare(`
SELECT
n.node_type,
rank
FROM nodes n
JOIN nodes_fts ON n.rowid = nodes_fts.rowid
SELECT node_type, rank FROM nodes_fts
WHERE nodes_fts MATCH 'webhook'
ORDER BY
CASE
WHEN LOWER(n.display_name) = LOWER('webhook') THEN 0
WHEN LOWER(n.display_name) LIKE LOWER('%webhook%') THEN 1
WHEN LOWER(n.node_type) LIKE LOWER('%webhook%') THEN 2
ELSE 3
END,
rank
ORDER BY rank
LIMIT 10
`).all();
expect(results.length).toBeGreaterThan(0);
// Exact match should be in top results (using production boosting logic with CASE-first ordering)
// Exact match should be in top results
const topResults = results.slice(0, 3).map((r: any) => r.node_type);
expect(topResults).toContain('nodes-base.webhook');
});