n8n-mcp 2.7.10 → 2.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -42
- package/data/nodes.db +0 -0
- package/dist/database/database-adapter.d.ts +1 -0
- package/dist/database/database-adapter.d.ts.map +1 -1
- package/dist/database/database-adapter.js +20 -0
- package/dist/database/database-adapter.js.map +1 -1
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +334 -10
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools-documentation.d.ts.map +1 -1
- package/dist/mcp/tools-documentation.js +832 -52
- package/dist/mcp/tools-documentation.js.map +1 -1
- package/dist/mcp/tools-n8n-manager.d.ts.map +1 -1
- package/dist/mcp/tools-n8n-manager.js +10 -112
- package/dist/mcp/tools-n8n-manager.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +42 -36
- package/dist/mcp/tools.js.map +1 -1
- package/dist/scripts/fetch-templates.d.ts.map +1 -1
- package/dist/scripts/fetch-templates.js +37 -0
- package/dist/scripts/fetch-templates.js.map +1 -1
- package/dist/scripts/test-error-handling-validation.d.ts +3 -0
- package/dist/scripts/test-error-handling-validation.d.ts.map +1 -0
- package/dist/scripts/test-error-handling-validation.js +340 -0
- package/dist/scripts/test-error-handling-validation.js.map +1 -0
- package/dist/scripts/test-node-level-properties.d.ts +3 -0
- package/dist/scripts/test-node-level-properties.d.ts.map +1 -0
- package/dist/scripts/test-node-level-properties.js +196 -0
- package/dist/scripts/test-node-level-properties.js.map +1 -0
- package/dist/services/config-validator.d.ts +2 -2
- package/dist/services/config-validator.d.ts.map +1 -1
- package/dist/services/config-validator.js +123 -5
- package/dist/services/config-validator.js.map +1 -1
- package/dist/services/enhanced-config-validator.d.ts +2 -0
- package/dist/services/enhanced-config-validator.d.ts.map +1 -1
- package/dist/services/enhanced-config-validator.js +31 -1
- package/dist/services/enhanced-config-validator.js.map +1 -1
- package/dist/services/example-generator.d.ts.map +1 -1
- package/dist/services/example-generator.js +442 -28
- package/dist/services/example-generator.js.map +1 -1
- package/dist/services/n8n-validation.d.ts +10 -10
- package/dist/services/node-specific-validators.d.ts +8 -1
- package/dist/services/node-specific-validators.d.ts.map +1 -1
- package/dist/services/node-specific-validators.js +608 -59
- package/dist/services/node-specific-validators.js.map +1 -1
- package/dist/services/task-templates.d.ts +1 -0
- package/dist/services/task-templates.d.ts.map +1 -1
- package/dist/services/task-templates.js +858 -16
- package/dist/services/task-templates.js.map +1 -1
- package/dist/services/workflow-diff-engine.d.ts.map +1 -1
- package/dist/services/workflow-diff-engine.js +1 -0
- package/dist/services/workflow-diff-engine.js.map +1 -1
- package/dist/services/workflow-validator.d.ts +9 -0
- package/dist/services/workflow-validator.d.ts.map +1 -1
- package/dist/services/workflow-validator.js +270 -0
- package/dist/services/workflow-validator.js.map +1 -1
- package/dist/sse-server.d.ts +8 -0
- package/dist/sse-server.d.ts.map +1 -0
- package/dist/sse-server.js +652 -0
- package/dist/sse-server.js.map +1 -0
- package/dist/templates/template-repository.d.ts +4 -0
- package/dist/templates/template-repository.d.ts.map +1 -1
- package/dist/templates/template-repository.js +119 -7
- package/dist/templates/template-repository.js.map +1 -1
- package/dist/templates/template-service.d.ts.map +1 -1
- package/dist/templates/template-service.js +2 -0
- package/dist/templates/template-service.js.map +1 -1
- package/dist/types/n8n-api.d.ts +2 -1
- package/dist/types/n8n-api.d.ts.map +1 -1
- package/dist/types/n8n-api.js.map +1 -1
- package/dist/types/sse.d.ts +42 -0
- package/dist/types/sse.d.ts.map +1 -0
- package/dist/types/sse.js +3 -0
- package/dist/types/sse.js.map +1 -0
- package/dist/utils/sse-session-manager.d.ts +23 -0
- package/dist/utils/sse-session-manager.d.ts.map +1 -0
- package/dist/utils/sse-session-manager.js +178 -0
- package/dist/utils/sse-session-manager.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
[](https://github.com/czlonkowski/n8n-mcp)
|
|
5
|
-
[](https://github.com/czlonkowski/n8n-mcp)
|
|
6
6
|
[](https://www.npmjs.com/package/n8n-mcp)
|
|
7
7
|
[](https://github.com/n8n-io/n8n)
|
|
8
8
|
[](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
|
@@ -20,10 +20,22 @@ n8n-MCP serves as a bridge between n8n's workflow automation platform and AI mod
|
|
|
20
20
|
- 🤖 **AI tools** - 263 AI-capable nodes detected with full documentation
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
## ⚠️ Important Safety Warning
|
|
24
|
+
|
|
25
|
+
**NEVER edit your production workflows directly with AI!** Always:
|
|
26
|
+
- 🔄 **Make a copy** of your workflow before using AI tools
|
|
27
|
+
- 🧪 **Test in development** environment first
|
|
28
|
+
- 💾 **Export backups** of important workflows
|
|
29
|
+
- ⚡ **Validate changes** before deploying to production
|
|
30
|
+
|
|
31
|
+
AI results can be unpredictable. Protect your work!
|
|
32
|
+
|
|
23
33
|
## 🚀 Quick Start
|
|
24
34
|
|
|
25
35
|
Get n8n-MCP running in 5 minutes:
|
|
26
36
|
|
|
37
|
+
[](https://youtu.be/5CccjiLLyaY?si=Z62SBGlw9G34IQnQ&t=343)
|
|
38
|
+
|
|
27
39
|
### Option 1: npx (Fastest - No Installation!) 🚀
|
|
28
40
|
|
|
29
41
|
**Prerequisites:** [Node.js](https://nodejs.org/) installed on your system
|
|
@@ -260,9 +272,10 @@ You are an expert in n8n automation software using n8n-MCP tools. Your role is t
|
|
|
260
272
|
|
|
261
273
|
## Core Workflow Process
|
|
262
274
|
|
|
263
|
-
1. **ALWAYS start with**: `tools_documentation()` to understand best practices and available tools.
|
|
275
|
+
1. **ALWAYS start new conversation with**: `tools_documentation()` to understand best practices and available tools.
|
|
264
276
|
|
|
265
277
|
2. **Discovery Phase** - Find the right nodes:
|
|
278
|
+
- Think deeply about user request and the logic you are going to build to fulfill it. Ask follow-up questions to clarify the user's intent, if something is unclear. Then, proceed with the rest of your instructions.
|
|
266
279
|
- `search_nodes({query: 'keyword'})` - Search by functionality
|
|
267
280
|
- `list_nodes({category: 'trigger'})` - Browse by category
|
|
268
281
|
- `list_ai_tools()` - See AI-capable nodes (remember: ANY node can be an AI tool!)
|
|
@@ -272,6 +285,7 @@ You are an expert in n8n automation software using n8n-MCP tools. Your role is t
|
|
|
272
285
|
- `search_node_properties(nodeType, 'auth')` - Find specific properties
|
|
273
286
|
- `get_node_for_task('send_email')` - Get pre-configured templates
|
|
274
287
|
- `get_node_documentation(nodeType)` - Human-readable docs when needed
|
|
288
|
+
- It is good common practice to show a visual representation of the workflow architecture to the user and asking for opinion, before moving forward.
|
|
275
289
|
|
|
276
290
|
4. **Pre-Validation Phase** - Validate BEFORE building:
|
|
277
291
|
- `validate_node_minimal(nodeType, config)` - Quick required fields check
|
|
@@ -283,7 +297,7 @@ You are an expert in n8n automation software using n8n-MCP tools. Your role is t
|
|
|
283
297
|
- Connect nodes with proper structure
|
|
284
298
|
- Add error handling where appropriate
|
|
285
299
|
- Use expressions like $json, $node["NodeName"].json
|
|
286
|
-
- Build the workflow in an artifact (unless the user asked to create in n8n instance)
|
|
300
|
+
- Build the workflow in an artifact for easy editing downstream (unless the user asked to create in n8n instance)
|
|
287
301
|
|
|
288
302
|
6. **Workflow Validation Phase** - Validate complete workflow:
|
|
289
303
|
- `validate_workflow(workflow)` - Complete validation including connections
|
|
@@ -299,7 +313,8 @@ You are an expert in n8n automation software using n8n-MCP tools. Your role is t
|
|
|
299
313
|
|
|
300
314
|
## Key Insights
|
|
301
315
|
|
|
302
|
-
- **
|
|
316
|
+
- **USE CODE NODE ONLY WHEN IT IS NECESSARY** - always prefer to use standard nodes over code node. Use code node only when you are sure you need it.
|
|
317
|
+
- **VALIDATE EARLY AND OFTEN** - Catch errors before they reach deployment
|
|
303
318
|
- **USE DIFF UPDATES** - Use n8n_update_partial_workflow for 80-90% token savings
|
|
304
319
|
- **ANY node can be an AI tool** - not just those with usableAsTool=true
|
|
305
320
|
- **Pre-validate configurations** - Use validate_node_minimal before building
|
|
@@ -565,44 +580,7 @@ Current database coverage (n8n v1.100.1):
|
|
|
565
580
|
|
|
566
581
|
## 🔄 Recent Updates
|
|
567
582
|
|
|
568
|
-
|
|
569
|
-
- ✅ **RENAMED**: `start_here_workflow_guide` → `tools_documentation` for clarity
|
|
570
|
-
- ✅ **NEW**: Depth parameter - Control documentation detail with "essentials" or "full"
|
|
571
|
-
- ✅ **NEW**: Per-tool documentation - Get help for any specific MCP tool by name
|
|
572
|
-
- ✅ **CONCISE**: Essential info by default, comprehensive docs on demand
|
|
573
|
-
- ✅ **LLM-FRIENDLY**: Plain text format instead of JSON for better readability
|
|
574
|
-
- ✅ **QUICK HELP**: Call without parameters for immediate quick reference
|
|
575
|
-
- ✅ **8 TOOLS DOCUMENTED**: Complete documentation for most commonly used tools
|
|
576
|
-
|
|
577
|
-
### v2.7.0 - Diff-Based Workflow Editing with Transactional Updates
|
|
578
|
-
- ✅ **NEW**: `n8n_update_partial_workflow` tool - Update workflows using diff operations
|
|
579
|
-
- ✅ **RENAMED**: `n8n_update_workflow` → `n8n_update_full_workflow` for clarity
|
|
580
|
-
- ✅ **80-90% TOKEN SAVINGS**: Only send changes, not entire workflow JSON
|
|
581
|
-
- ✅ **13 OPERATIONS**: addNode, removeNode, updateNode, moveNode, enable/disable, connections, settings, tags
|
|
582
|
-
- ✅ **TRANSACTIONAL**: Two-pass processing allows adding nodes and connections in any order
|
|
583
|
-
- ✅ **5 OPERATION LIMIT**: Ensures reliability and atomic updates
|
|
584
|
-
- ✅ **VALIDATION MODE**: Test changes with `validateOnly: true` before applying
|
|
585
|
-
- ✅ **IMPROVED DOCS**: Comprehensive parameter documentation and examples
|
|
586
|
-
|
|
587
|
-
### v2.6.3 - n8n Instance Workflow Validation
|
|
588
|
-
- ✅ **NEW**: `n8n_validate_workflow` tool - Validate workflows directly from n8n instance by ID
|
|
589
|
-
- ✅ **FETCHES**: Retrieves workflow from n8n API and runs comprehensive validation
|
|
590
|
-
- ✅ **CONSISTENT**: Uses same WorkflowValidator for reliability
|
|
591
|
-
- ✅ **FLEXIBLE**: Supports all validation profiles and options
|
|
592
|
-
- ✅ **INTEGRATED**: Part of complete workflow lifecycle management
|
|
593
|
-
- ✅ **SIMPLE**: AI agents need only workflow ID, no JSON required
|
|
594
|
-
|
|
595
|
-
### v2.6.2 - Enhanced Workflow Creation Validation
|
|
596
|
-
- ✅ **NEW**: Node type validation - Verifies node types actually exist in n8n
|
|
597
|
-
- ✅ **FIXED**: Critical issue with `nodes-base.webhook` validation - now caught before database lookup
|
|
598
|
-
- ✅ **NEW**: Smart suggestions for common mistakes (e.g., `webhook` → `n8n-nodes-base.webhook`)
|
|
599
|
-
- ✅ **NEW**: Minimum viable workflow validation - Prevents single-node workflows (except webhooks)
|
|
600
|
-
- ✅ **NEW**: Empty connection detection - Catches multi-node workflows with no connections
|
|
601
|
-
- ✅ **ENHANCED**: Error messages with clear guidance and examples
|
|
602
|
-
- ✅ **PREVENTS**: Broken workflows that show as question marks in n8n UI
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
See [CHANGELOG.md](./docs/CHANGELOG.md) for full version history.
|
|
583
|
+
See [CHANGELOG.md](./docs/CHANGELOG.md) for full version history and recent changes.
|
|
606
584
|
|
|
607
585
|
## ⚠️ Known Issues
|
|
608
586
|
|
package/data/nodes.db
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-adapter.d.ts","sourceRoot":"","sources":["../../src/database/database-adapter.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACxC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"database-adapter.d.ts","sourceRoot":"","sources":["../../src/database/database-adapter.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACxC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/B,gBAAgB,IAAI,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC;IACjC,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IAC3B,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;IAC7B,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACjD,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAMD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAoDpF"}
|
|
@@ -141,6 +141,16 @@ class BetterSQLiteAdapter {
|
|
|
141
141
|
transaction(fn) {
|
|
142
142
|
return this.db.transaction(fn)();
|
|
143
143
|
}
|
|
144
|
+
checkFTS5Support() {
|
|
145
|
+
try {
|
|
146
|
+
this.exec("CREATE VIRTUAL TABLE IF NOT EXISTS test_fts5 USING fts5(content);");
|
|
147
|
+
this.exec("DROP TABLE IF EXISTS test_fts5;");
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
144
154
|
}
|
|
145
155
|
class SQLJSAdapter {
|
|
146
156
|
constructor(db, dbPath) {
|
|
@@ -186,6 +196,16 @@ class SQLJSAdapter {
|
|
|
186
196
|
throw error;
|
|
187
197
|
}
|
|
188
198
|
}
|
|
199
|
+
checkFTS5Support() {
|
|
200
|
+
try {
|
|
201
|
+
this.exec("CREATE VIRTUAL TABLE IF NOT EXISTS test_fts5 USING fts5(content);");
|
|
202
|
+
this.exec("DROP TABLE IF EXISTS test_fts5;");
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
189
209
|
scheduleSave() {
|
|
190
210
|
if (this.saveTimer) {
|
|
191
211
|
clearTimeout(this.saveTimer);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-adapter.js","sourceRoot":"","sources":["../../src/database/database-adapter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"database-adapter.js","sourceRoot":"","sources":["../../src/database/database-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -12,7 +12,14 @@ export declare class N8NDocumentationMCPServer {
|
|
|
12
12
|
private listNodes;
|
|
13
13
|
private getNodeInfo;
|
|
14
14
|
private searchNodes;
|
|
15
|
+
private searchNodesFTS;
|
|
16
|
+
private searchNodesFuzzy;
|
|
17
|
+
private calculateFuzzyScore;
|
|
18
|
+
private getEditDistance;
|
|
19
|
+
private searchNodesLIKE;
|
|
15
20
|
private calculateRelevance;
|
|
21
|
+
private calculateRelevanceScore;
|
|
22
|
+
private rankSearchResults;
|
|
16
23
|
private listAITools;
|
|
17
24
|
private getNodeDocumentation;
|
|
18
25
|
private getDatabaseStatistics;
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AA+CA,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAgC;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAAqB;;YAmDpB,kBAAkB;YAYlB,iBAAiB;IAO/B,OAAO,CAAC,aAAa;YA+JP,SAAS;YA2DT,WAAW;YA6CX,WAAW;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AA+CA,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAgC;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAAqB;;YAmDpB,kBAAkB;YAYlB,iBAAiB;IAO/B,OAAO,CAAC,aAAa;YA+JP,SAAS;YA2DT,WAAW;YA6CX,WAAW;YA4BX,cAAc;YAgId,gBAAgB;IAoD9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IAmE7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;YA8CpB,qBAAqB;YAuCrB,iBAAiB;YA+EjB,oBAAoB;YAoDpB,cAAc;IAqC5B,OAAO,CAAC,gBAAgB;YAiBV,SAAS;YA6CT,kBAAkB;YA4DlB,uBAAuB;YAoDvB,iBAAiB;IAkE/B,OAAO,CAAC,uBAAuB;IAwD/B,OAAO,CAAC,iBAAiB;YAoDX,mBAAmB;YAgGnB,qBAAqB;IAS7B,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9B,iBAAiB;YAqBjB,WAAW;YAmBX,eAAe;YAqBf,mBAAmB;IAuBjC,OAAO,CAAC,kBAAkB;YAiBZ,gBAAgB;YA2DhB,2BAA2B;YAiE3B,2BAA2B;IAyEnC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyB3B"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -184,7 +184,7 @@ class N8NDocumentationMCPServer {
|
|
|
184
184
|
case 'get_node_info':
|
|
185
185
|
return this.getNodeInfo(args.nodeType);
|
|
186
186
|
case 'search_nodes':
|
|
187
|
-
return this.searchNodes(args.query, args.limit);
|
|
187
|
+
return this.searchNodes(args.query, args.limit, { mode: args.mode });
|
|
188
188
|
case 'list_ai_tools':
|
|
189
189
|
return this.listAITools();
|
|
190
190
|
case 'get_node_documentation':
|
|
@@ -346,8 +346,226 @@ class N8NDocumentationMCPServer {
|
|
|
346
346
|
aiToolCapabilities
|
|
347
347
|
};
|
|
348
348
|
}
|
|
349
|
-
async searchNodes(query, limit = 20) {
|
|
349
|
+
async searchNodes(query, limit = 20, options) {
|
|
350
350
|
await this.ensureInitialized();
|
|
351
|
+
if (!this.db)
|
|
352
|
+
throw new Error('Database not initialized');
|
|
353
|
+
const searchMode = options?.mode || 'OR';
|
|
354
|
+
const ftsExists = this.db.prepare(`
|
|
355
|
+
SELECT name FROM sqlite_master
|
|
356
|
+
WHERE type='table' AND name='nodes_fts'
|
|
357
|
+
`).get();
|
|
358
|
+
if (ftsExists) {
|
|
359
|
+
return this.searchNodesFTS(query, limit, searchMode);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
return this.searchNodesLIKE(query, limit);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
async searchNodesFTS(query, limit, mode) {
|
|
366
|
+
if (!this.db)
|
|
367
|
+
throw new Error('Database not initialized');
|
|
368
|
+
const cleanedQuery = query.trim();
|
|
369
|
+
if (!cleanedQuery) {
|
|
370
|
+
return { query, results: [], totalCount: 0 };
|
|
371
|
+
}
|
|
372
|
+
if (mode === 'FUZZY') {
|
|
373
|
+
return this.searchNodesFuzzy(cleanedQuery, limit);
|
|
374
|
+
}
|
|
375
|
+
let ftsQuery;
|
|
376
|
+
if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) {
|
|
377
|
+
ftsQuery = cleanedQuery;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
const words = cleanedQuery.split(/\s+/).filter(w => w.length > 0);
|
|
381
|
+
switch (mode) {
|
|
382
|
+
case 'AND':
|
|
383
|
+
ftsQuery = words.join(' AND ');
|
|
384
|
+
break;
|
|
385
|
+
case 'OR':
|
|
386
|
+
default:
|
|
387
|
+
ftsQuery = words.join(' OR ');
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
const nodes = this.db.prepare(`
|
|
393
|
+
SELECT
|
|
394
|
+
n.*,
|
|
395
|
+
rank
|
|
396
|
+
FROM nodes n
|
|
397
|
+
JOIN nodes_fts ON n.rowid = nodes_fts.rowid
|
|
398
|
+
WHERE nodes_fts MATCH ?
|
|
399
|
+
ORDER BY
|
|
400
|
+
rank,
|
|
401
|
+
CASE
|
|
402
|
+
WHEN n.display_name = ? THEN 0
|
|
403
|
+
WHEN n.display_name LIKE ? THEN 1
|
|
404
|
+
WHEN n.node_type LIKE ? THEN 2
|
|
405
|
+
ELSE 3
|
|
406
|
+
END,
|
|
407
|
+
n.display_name
|
|
408
|
+
LIMIT ?
|
|
409
|
+
`).all(ftsQuery, cleanedQuery, `%${cleanedQuery}%`, `%${cleanedQuery}%`, limit);
|
|
410
|
+
const scoredNodes = nodes.map(node => {
|
|
411
|
+
const relevanceScore = this.calculateRelevanceScore(node, cleanedQuery);
|
|
412
|
+
return { ...node, relevanceScore };
|
|
413
|
+
});
|
|
414
|
+
scoredNodes.sort((a, b) => {
|
|
415
|
+
if (a.display_name.toLowerCase() === cleanedQuery.toLowerCase())
|
|
416
|
+
return -1;
|
|
417
|
+
if (b.display_name.toLowerCase() === cleanedQuery.toLowerCase())
|
|
418
|
+
return 1;
|
|
419
|
+
if (a.relevanceScore !== b.relevanceScore) {
|
|
420
|
+
return b.relevanceScore - a.relevanceScore;
|
|
421
|
+
}
|
|
422
|
+
return a.rank - b.rank;
|
|
423
|
+
});
|
|
424
|
+
const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest');
|
|
425
|
+
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
|
|
426
|
+
logger_1.logger.debug('FTS missed HTTP Request node, augmenting with LIKE search');
|
|
427
|
+
return this.searchNodesLIKE(query, limit);
|
|
428
|
+
}
|
|
429
|
+
const result = {
|
|
430
|
+
query,
|
|
431
|
+
results: scoredNodes.map(node => ({
|
|
432
|
+
nodeType: node.node_type,
|
|
433
|
+
displayName: node.display_name,
|
|
434
|
+
description: node.description,
|
|
435
|
+
category: node.category,
|
|
436
|
+
package: node.package_name,
|
|
437
|
+
relevance: this.calculateRelevance(node, cleanedQuery)
|
|
438
|
+
})),
|
|
439
|
+
totalCount: scoredNodes.length
|
|
440
|
+
};
|
|
441
|
+
if (mode !== 'OR') {
|
|
442
|
+
result.mode = mode;
|
|
443
|
+
}
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
logger_1.logger.warn('FTS5 search failed, falling back to LIKE search:', error.message);
|
|
448
|
+
if (error.message.includes('syntax error') || error.message.includes('fts5')) {
|
|
449
|
+
logger_1.logger.warn(`FTS5 syntax error for query "${query}" in mode ${mode}`);
|
|
450
|
+
const likeResult = await this.searchNodesLIKE(query, limit);
|
|
451
|
+
return {
|
|
452
|
+
...likeResult,
|
|
453
|
+
mode
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
return this.searchNodesLIKE(query, limit);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async searchNodesFuzzy(query, limit) {
|
|
460
|
+
if (!this.db)
|
|
461
|
+
throw new Error('Database not initialized');
|
|
462
|
+
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
|
463
|
+
if (words.length === 0) {
|
|
464
|
+
return { query, results: [], totalCount: 0, mode: 'FUZZY' };
|
|
465
|
+
}
|
|
466
|
+
const candidateNodes = this.db.prepare(`
|
|
467
|
+
SELECT * FROM nodes
|
|
468
|
+
`).all();
|
|
469
|
+
const scoredNodes = candidateNodes.map(node => {
|
|
470
|
+
const score = this.calculateFuzzyScore(node, query);
|
|
471
|
+
return { node, score };
|
|
472
|
+
});
|
|
473
|
+
const matchingNodes = scoredNodes
|
|
474
|
+
.filter(item => item.score >= 200)
|
|
475
|
+
.sort((a, b) => b.score - a.score)
|
|
476
|
+
.slice(0, limit)
|
|
477
|
+
.map(item => item.node);
|
|
478
|
+
if (matchingNodes.length === 0) {
|
|
479
|
+
const topScores = scoredNodes
|
|
480
|
+
.sort((a, b) => b.score - a.score)
|
|
481
|
+
.slice(0, 5);
|
|
482
|
+
logger_1.logger.debug(`FUZZY search for "${query}" - no matches above 400. Top scores:`, topScores.map(s => ({ name: s.node.display_name, score: s.score })));
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
query,
|
|
486
|
+
mode: 'FUZZY',
|
|
487
|
+
results: matchingNodes.map(node => ({
|
|
488
|
+
nodeType: node.node_type,
|
|
489
|
+
displayName: node.display_name,
|
|
490
|
+
description: node.description,
|
|
491
|
+
category: node.category,
|
|
492
|
+
package: node.package_name
|
|
493
|
+
})),
|
|
494
|
+
totalCount: matchingNodes.length
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
calculateFuzzyScore(node, query) {
|
|
498
|
+
const queryLower = query.toLowerCase();
|
|
499
|
+
const displayNameLower = node.display_name.toLowerCase();
|
|
500
|
+
const nodeTypeLower = node.node_type.toLowerCase();
|
|
501
|
+
const nodeTypeClean = nodeTypeLower.replace(/^nodes-base\./, '').replace(/^nodes-langchain\./, '');
|
|
502
|
+
if (displayNameLower === queryLower || nodeTypeClean === queryLower) {
|
|
503
|
+
return 1000;
|
|
504
|
+
}
|
|
505
|
+
const nameDistance = this.getEditDistance(queryLower, displayNameLower);
|
|
506
|
+
const typeDistance = this.getEditDistance(queryLower, nodeTypeClean);
|
|
507
|
+
const nameWords = displayNameLower.split(/\s+/);
|
|
508
|
+
let minWordDistance = Infinity;
|
|
509
|
+
for (const word of nameWords) {
|
|
510
|
+
const distance = this.getEditDistance(queryLower, word);
|
|
511
|
+
if (distance < minWordDistance) {
|
|
512
|
+
minWordDistance = distance;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const bestDistance = Math.min(nameDistance, typeDistance, minWordDistance);
|
|
516
|
+
let matchedLen = queryLower.length;
|
|
517
|
+
if (minWordDistance === bestDistance) {
|
|
518
|
+
for (const word of nameWords) {
|
|
519
|
+
if (this.getEditDistance(queryLower, word) === minWordDistance) {
|
|
520
|
+
matchedLen = Math.max(queryLower.length, word.length);
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else if (typeDistance === bestDistance) {
|
|
526
|
+
matchedLen = Math.max(queryLower.length, nodeTypeClean.length);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
matchedLen = Math.max(queryLower.length, displayNameLower.length);
|
|
530
|
+
}
|
|
531
|
+
const similarity = 1 - (bestDistance / matchedLen);
|
|
532
|
+
if (displayNameLower.includes(queryLower) || nodeTypeClean.includes(queryLower)) {
|
|
533
|
+
return 800 + (similarity * 100);
|
|
534
|
+
}
|
|
535
|
+
if (displayNameLower.startsWith(queryLower) ||
|
|
536
|
+
nodeTypeClean.startsWith(queryLower) ||
|
|
537
|
+
nameWords.some(w => w.startsWith(queryLower))) {
|
|
538
|
+
return 700 + (similarity * 100);
|
|
539
|
+
}
|
|
540
|
+
if (bestDistance <= 2) {
|
|
541
|
+
return 500 + ((2 - bestDistance) * 100) + (similarity * 50);
|
|
542
|
+
}
|
|
543
|
+
if (bestDistance <= 3 && queryLower.length >= 4) {
|
|
544
|
+
return 400 + ((3 - bestDistance) * 50) + (similarity * 50);
|
|
545
|
+
}
|
|
546
|
+
return similarity * 300;
|
|
547
|
+
}
|
|
548
|
+
getEditDistance(s1, s2) {
|
|
549
|
+
const m = s1.length;
|
|
550
|
+
const n = s2.length;
|
|
551
|
+
const dp = Array(m + 1).fill(null).map(() => Array(n + 1).fill(0));
|
|
552
|
+
for (let i = 0; i <= m; i++)
|
|
553
|
+
dp[i][0] = i;
|
|
554
|
+
for (let j = 0; j <= n; j++)
|
|
555
|
+
dp[0][j] = j;
|
|
556
|
+
for (let i = 1; i <= m; i++) {
|
|
557
|
+
for (let j = 1; j <= n; j++) {
|
|
558
|
+
if (s1[i - 1] === s2[j - 1]) {
|
|
559
|
+
dp[i][j] = dp[i - 1][j - 1];
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return dp[m][n];
|
|
567
|
+
}
|
|
568
|
+
async searchNodesLIKE(query, limit) {
|
|
351
569
|
if (!this.db)
|
|
352
570
|
throw new Error('Database not initialized');
|
|
353
571
|
if (query.startsWith('"') && query.endsWith('"')) {
|
|
@@ -355,19 +573,19 @@ class N8NDocumentationMCPServer {
|
|
|
355
573
|
const nodes = this.db.prepare(`
|
|
356
574
|
SELECT * FROM nodes
|
|
357
575
|
WHERE node_type LIKE ? OR display_name LIKE ? OR description LIKE ?
|
|
358
|
-
ORDER BY display_name
|
|
359
576
|
LIMIT ?
|
|
360
|
-
`).all(`%${exactPhrase}%`, `%${exactPhrase}%`, `%${exactPhrase}%`, limit);
|
|
577
|
+
`).all(`%${exactPhrase}%`, `%${exactPhrase}%`, `%${exactPhrase}%`, limit * 3);
|
|
578
|
+
const rankedNodes = this.rankSearchResults(nodes, exactPhrase, limit);
|
|
361
579
|
return {
|
|
362
580
|
query,
|
|
363
|
-
results:
|
|
581
|
+
results: rankedNodes.map(node => ({
|
|
364
582
|
nodeType: node.node_type,
|
|
365
583
|
displayName: node.display_name,
|
|
366
584
|
description: node.description,
|
|
367
585
|
category: node.category,
|
|
368
586
|
package: node.package_name
|
|
369
587
|
})),
|
|
370
|
-
totalCount:
|
|
588
|
+
totalCount: rankedNodes.length
|
|
371
589
|
};
|
|
372
590
|
}
|
|
373
591
|
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
|
@@ -376,23 +594,23 @@ class N8NDocumentationMCPServer {
|
|
|
376
594
|
}
|
|
377
595
|
const conditions = words.map(() => '(node_type LIKE ? OR display_name LIKE ? OR description LIKE ?)').join(' OR ');
|
|
378
596
|
const params = words.flatMap(w => [`%${w}%`, `%${w}%`, `%${w}%`]);
|
|
379
|
-
params.push(limit);
|
|
597
|
+
params.push(limit * 3);
|
|
380
598
|
const nodes = this.db.prepare(`
|
|
381
599
|
SELECT DISTINCT * FROM nodes
|
|
382
600
|
WHERE ${conditions}
|
|
383
|
-
ORDER BY display_name
|
|
384
601
|
LIMIT ?
|
|
385
602
|
`).all(...params);
|
|
603
|
+
const rankedNodes = this.rankSearchResults(nodes, query, limit);
|
|
386
604
|
return {
|
|
387
605
|
query,
|
|
388
|
-
results:
|
|
606
|
+
results: rankedNodes.map(node => ({
|
|
389
607
|
nodeType: node.node_type,
|
|
390
608
|
displayName: node.display_name,
|
|
391
609
|
description: node.description,
|
|
392
610
|
category: node.category,
|
|
393
611
|
package: node.package_name
|
|
394
612
|
})),
|
|
395
|
-
totalCount:
|
|
613
|
+
totalCount: rankedNodes.length
|
|
396
614
|
};
|
|
397
615
|
}
|
|
398
616
|
calculateRelevance(node, query) {
|
|
@@ -405,6 +623,112 @@ class N8NDocumentationMCPServer {
|
|
|
405
623
|
return 'medium';
|
|
406
624
|
return 'low';
|
|
407
625
|
}
|
|
626
|
+
calculateRelevanceScore(node, query) {
|
|
627
|
+
const query_lower = query.toLowerCase();
|
|
628
|
+
const name_lower = node.display_name.toLowerCase();
|
|
629
|
+
const type_lower = node.node_type.toLowerCase();
|
|
630
|
+
const type_without_prefix = type_lower.replace(/^nodes-base\./, '').replace(/^nodes-langchain\./, '');
|
|
631
|
+
let score = 0;
|
|
632
|
+
if (name_lower === query_lower) {
|
|
633
|
+
score = 1000;
|
|
634
|
+
}
|
|
635
|
+
else if (type_without_prefix === query_lower) {
|
|
636
|
+
score = 950;
|
|
637
|
+
}
|
|
638
|
+
else if (query_lower === 'webhook' && node.node_type === 'nodes-base.webhook') {
|
|
639
|
+
score = 900;
|
|
640
|
+
}
|
|
641
|
+
else if ((query_lower === 'http' || query_lower === 'http request' || query_lower === 'http call') && node.node_type === 'nodes-base.httpRequest') {
|
|
642
|
+
score = 900;
|
|
643
|
+
}
|
|
644
|
+
else if (query_lower.includes('http') && query_lower.includes('call') && node.node_type === 'nodes-base.httpRequest') {
|
|
645
|
+
score = 890;
|
|
646
|
+
}
|
|
647
|
+
else if (query_lower.includes('http') && node.node_type === 'nodes-base.httpRequest') {
|
|
648
|
+
score = 850;
|
|
649
|
+
}
|
|
650
|
+
else if (query_lower.includes('webhook') && node.node_type === 'nodes-base.webhook') {
|
|
651
|
+
score = 850;
|
|
652
|
+
}
|
|
653
|
+
else if (name_lower.startsWith(query_lower)) {
|
|
654
|
+
score = 800;
|
|
655
|
+
}
|
|
656
|
+
else if (new RegExp(`\\b${query_lower}\\b`, 'i').test(node.display_name)) {
|
|
657
|
+
score = 700;
|
|
658
|
+
}
|
|
659
|
+
else if (name_lower.includes(query_lower)) {
|
|
660
|
+
score = 600;
|
|
661
|
+
}
|
|
662
|
+
else if (type_without_prefix.includes(query_lower)) {
|
|
663
|
+
score = 500;
|
|
664
|
+
}
|
|
665
|
+
else if (node.description?.toLowerCase().includes(query_lower)) {
|
|
666
|
+
score = 400;
|
|
667
|
+
}
|
|
668
|
+
return score;
|
|
669
|
+
}
|
|
670
|
+
rankSearchResults(nodes, query, limit) {
|
|
671
|
+
const query_lower = query.toLowerCase();
|
|
672
|
+
const scoredNodes = nodes.map(node => {
|
|
673
|
+
const name_lower = node.display_name.toLowerCase();
|
|
674
|
+
const type_lower = node.node_type.toLowerCase();
|
|
675
|
+
const type_without_prefix = type_lower.replace(/^nodes-base\./, '').replace(/^nodes-langchain\./, '');
|
|
676
|
+
let score = 0;
|
|
677
|
+
if (name_lower === query_lower) {
|
|
678
|
+
score = 1000;
|
|
679
|
+
}
|
|
680
|
+
else if (type_without_prefix === query_lower) {
|
|
681
|
+
score = 950;
|
|
682
|
+
}
|
|
683
|
+
else if (query_lower === 'webhook' && node.node_type === 'nodes-base.webhook') {
|
|
684
|
+
score = 900;
|
|
685
|
+
}
|
|
686
|
+
else if ((query_lower === 'http' || query_lower === 'http request' || query_lower === 'http call') && node.node_type === 'nodes-base.httpRequest') {
|
|
687
|
+
score = 900;
|
|
688
|
+
}
|
|
689
|
+
else if (query_lower.includes('webhook') && node.node_type === 'nodes-base.webhook') {
|
|
690
|
+
score = 850;
|
|
691
|
+
}
|
|
692
|
+
else if (query_lower.includes('http') && node.node_type === 'nodes-base.httpRequest') {
|
|
693
|
+
score = 850;
|
|
694
|
+
}
|
|
695
|
+
else if (name_lower.startsWith(query_lower)) {
|
|
696
|
+
score = 800;
|
|
697
|
+
}
|
|
698
|
+
else if (new RegExp(`\\b${query_lower}\\b`, 'i').test(node.display_name)) {
|
|
699
|
+
score = 700;
|
|
700
|
+
}
|
|
701
|
+
else if (name_lower.includes(query_lower)) {
|
|
702
|
+
score = 600;
|
|
703
|
+
}
|
|
704
|
+
else if (type_without_prefix.includes(query_lower)) {
|
|
705
|
+
score = 500;
|
|
706
|
+
}
|
|
707
|
+
else if (node.description?.toLowerCase().includes(query_lower)) {
|
|
708
|
+
score = 400;
|
|
709
|
+
}
|
|
710
|
+
const words = query_lower.split(/\s+/).filter(w => w.length > 0);
|
|
711
|
+
if (words.length > 1) {
|
|
712
|
+
const allWordsInName = words.every(word => name_lower.includes(word));
|
|
713
|
+
const allWordsInDesc = words.every(word => node.description?.toLowerCase().includes(word));
|
|
714
|
+
if (allWordsInName)
|
|
715
|
+
score += 200;
|
|
716
|
+
else if (allWordsInDesc)
|
|
717
|
+
score += 100;
|
|
718
|
+
if (query_lower === 'http call' && name_lower === 'http request') {
|
|
719
|
+
score = 920;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return { node, score };
|
|
723
|
+
});
|
|
724
|
+
scoredNodes.sort((a, b) => {
|
|
725
|
+
if (a.score !== b.score) {
|
|
726
|
+
return b.score - a.score;
|
|
727
|
+
}
|
|
728
|
+
return a.node.display_name.localeCompare(b.node.display_name);
|
|
729
|
+
});
|
|
730
|
+
return scoredNodes.slice(0, limit).map(item => item.node);
|
|
731
|
+
}
|
|
408
732
|
async listAITools() {
|
|
409
733
|
await this.ensureInitialized();
|
|
410
734
|
if (!this.repository)
|