n8n-mcp 2.14.7 → 2.15.0
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/data/nodes.db +0 -0
- package/dist/mcp/server.d.ts +0 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +137 -45
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-docs/index.d.ts.map +1 -1
- package/dist/mcp/tool-docs/index.js +0 -1
- package/dist/mcp/tool-docs/index.js.map +1 -1
- package/dist/mcp/tool-docs/templates/index.d.ts +0 -1
- package/dist/mcp/tool-docs/templates/index.d.ts.map +1 -1
- package/dist/mcp/tool-docs/templates/index.js +1 -3
- package/dist/mcp/tool-docs/templates/index.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +12 -16
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp-tools-engine.d.ts +0 -1
- package/dist/mcp-tools-engine.d.ts.map +1 -1
- package/dist/mcp-tools-engine.js +0 -4
- package/dist/mcp-tools-engine.js.map +1 -1
- package/dist/scripts/fetch-templates.d.ts +1 -1
- package/dist/scripts/fetch-templates.d.ts.map +1 -1
- package/dist/scripts/fetch-templates.js +147 -4
- package/dist/scripts/fetch-templates.js.map +1 -1
- package/dist/services/task-templates.d.ts.map +1 -1
- package/dist/services/task-templates.js.map +1 -1
- package/package.json +1 -1
package/data/nodes.db
CHANGED
|
Binary file
|
package/dist/mcp/server.d.ts
CHANGED
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":"AAqCA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAqB5D,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;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,qBAAqB,CAAsB;gBAEvC,eAAe,CAAC,EAAE,eAAe;YA2D/B,kBAAkB;YAsBlB,wBAAwB;YAgBxB,iBAAiB;IAO/B,OAAO,CAAC,aAAa;IA+QrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IAqE1B,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,qBAAqB;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAqCA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAqB5D,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;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,qBAAqB,CAAsB;gBAEvC,eAAe,CAAC,EAAE,eAAe;YA2D/B,kBAAkB;YAsBlB,wBAAwB;YAgBxB,iBAAiB;IAO/B,OAAO,CAAC,aAAa;IA+QrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IAqE1B,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,qBAAqB;YAiSf,SAAS;YA2DT,WAAW;YAiEX,WAAW;YAyCX,cAAc;YAyKd,gBAAgB;IAqD9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IAqI7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;YA2EpB,qBAAqB;YAwDrB,iBAAiB;YA6HjB,oBAAoB;IAsDlC,OAAO,CAAC,gBAAgB;YAiBV,SAAS;YA6CT,kBAAkB;YA+DlB,uBAAuB;YAsDvB,iBAAiB;IAqE/B,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,uBAAuB;IAwD/B,OAAO,CAAC,iBAAiB;YAoDX,mBAAmB;YAkGnB,qBAAqB;IAS7B,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9B,aAAa;YAcb,iBAAiB;YAoBjB,WAAW;YAwBX,eAAe;YAqBf,mBAAmB;YAwBnB,yBAAyB;IA4CvC,OAAO,CAAC,kBAAkB;YAiBZ,gBAAgB;YA6HhB,2BAA2B;YAiE3B,2BAA2B;IAyEnC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAuBhC"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -556,7 +556,7 @@ class N8NDocumentationMCPServer {
|
|
|
556
556
|
case 'search_nodes':
|
|
557
557
|
this.validateToolParams(name, args, ['query']);
|
|
558
558
|
const limit = args.limit !== undefined ? Number(args.limit) || 20 : 20;
|
|
559
|
-
return this.searchNodes(args.query, limit, { mode: args.mode });
|
|
559
|
+
return this.searchNodes(args.query, limit, { mode: args.mode, includeExamples: args.includeExamples });
|
|
560
560
|
case 'list_ai_tools':
|
|
561
561
|
return this.listAITools();
|
|
562
562
|
case 'get_node_documentation':
|
|
@@ -566,14 +566,11 @@ class N8NDocumentationMCPServer {
|
|
|
566
566
|
return this.getDatabaseStatistics();
|
|
567
567
|
case 'get_node_essentials':
|
|
568
568
|
this.validateToolParams(name, args, ['nodeType']);
|
|
569
|
-
return this.getNodeEssentials(args.nodeType);
|
|
569
|
+
return this.getNodeEssentials(args.nodeType, args.includeExamples);
|
|
570
570
|
case 'search_node_properties':
|
|
571
571
|
this.validateToolParams(name, args, ['nodeType', 'query']);
|
|
572
572
|
const maxResults = args.maxResults !== undefined ? Number(args.maxResults) || 20 : 20;
|
|
573
573
|
return this.searchNodeProperties(args.nodeType, args.query, maxResults);
|
|
574
|
-
case 'get_node_for_task':
|
|
575
|
-
this.validateToolParams(name, args, ['task']);
|
|
576
|
-
return this.getNodeForTask(args.task);
|
|
577
574
|
case 'list_tasks':
|
|
578
575
|
return this.listTasks(args.category);
|
|
579
576
|
case 'validate_node_operation':
|
|
@@ -847,13 +844,15 @@ class N8NDocumentationMCPServer {
|
|
|
847
844
|
WHERE type='table' AND name='nodes_fts'
|
|
848
845
|
`).get();
|
|
849
846
|
if (ftsExists) {
|
|
850
|
-
|
|
847
|
+
logger_1.logger.debug(`Using FTS5 search with includeExamples=${options?.includeExamples}`);
|
|
848
|
+
return this.searchNodesFTS(normalizedQuery, limit, searchMode, options);
|
|
851
849
|
}
|
|
852
850
|
else {
|
|
853
|
-
|
|
851
|
+
logger_1.logger.debug('Using LIKE search (no FTS5)');
|
|
852
|
+
return this.searchNodesLIKE(normalizedQuery, limit, options);
|
|
854
853
|
}
|
|
855
854
|
}
|
|
856
|
-
async searchNodesFTS(query, limit, mode) {
|
|
855
|
+
async searchNodesFTS(query, limit, mode, options) {
|
|
857
856
|
if (!this.db)
|
|
858
857
|
throw new Error('Database not initialized');
|
|
859
858
|
const cleanedQuery = query.trim();
|
|
@@ -933,6 +932,32 @@ class N8NDocumentationMCPServer {
|
|
|
933
932
|
if (mode !== 'OR') {
|
|
934
933
|
result.mode = mode;
|
|
935
934
|
}
|
|
935
|
+
if (options && options.includeExamples) {
|
|
936
|
+
try {
|
|
937
|
+
for (const nodeResult of result.results) {
|
|
938
|
+
const examples = this.db.prepare(`
|
|
939
|
+
SELECT
|
|
940
|
+
parameters_json,
|
|
941
|
+
template_name,
|
|
942
|
+
template_views
|
|
943
|
+
FROM template_node_configs
|
|
944
|
+
WHERE node_type = ?
|
|
945
|
+
ORDER BY rank
|
|
946
|
+
LIMIT 2
|
|
947
|
+
`).all(nodeResult.workflowNodeType);
|
|
948
|
+
if (examples.length > 0) {
|
|
949
|
+
nodeResult.examples = examples.map((ex) => ({
|
|
950
|
+
configuration: JSON.parse(ex.parameters_json),
|
|
951
|
+
template: ex.template_name,
|
|
952
|
+
views: ex.template_views
|
|
953
|
+
}));
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
catch (error) {
|
|
958
|
+
logger_1.logger.error(`Failed to add examples:`, error);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
936
961
|
telemetry_1.telemetry.trackSearchQuery(query, scoredNodes.length, mode ?? 'OR');
|
|
937
962
|
return result;
|
|
938
963
|
}
|
|
@@ -1060,18 +1085,18 @@ class N8NDocumentationMCPServer {
|
|
|
1060
1085
|
}
|
|
1061
1086
|
return dp[m][n];
|
|
1062
1087
|
}
|
|
1063
|
-
async searchNodesLIKE(query, limit) {
|
|
1088
|
+
async searchNodesLIKE(query, limit, options) {
|
|
1064
1089
|
if (!this.db)
|
|
1065
1090
|
throw new Error('Database not initialized');
|
|
1066
1091
|
if (query.startsWith('"') && query.endsWith('"')) {
|
|
1067
1092
|
const exactPhrase = query.slice(1, -1);
|
|
1068
1093
|
const nodes = this.db.prepare(`
|
|
1069
|
-
SELECT * FROM nodes
|
|
1094
|
+
SELECT * FROM nodes
|
|
1070
1095
|
WHERE node_type LIKE ? OR display_name LIKE ? OR description LIKE ?
|
|
1071
1096
|
LIMIT ?
|
|
1072
1097
|
`).all(`%${exactPhrase}%`, `%${exactPhrase}%`, `%${exactPhrase}%`, limit * 3);
|
|
1073
1098
|
const rankedNodes = this.rankSearchResults(nodes, exactPhrase, limit);
|
|
1074
|
-
|
|
1099
|
+
const result = {
|
|
1075
1100
|
query,
|
|
1076
1101
|
results: rankedNodes.map(node => ({
|
|
1077
1102
|
nodeType: node.node_type,
|
|
@@ -1083,6 +1108,33 @@ class N8NDocumentationMCPServer {
|
|
|
1083
1108
|
})),
|
|
1084
1109
|
totalCount: rankedNodes.length
|
|
1085
1110
|
};
|
|
1111
|
+
if (options?.includeExamples) {
|
|
1112
|
+
for (const nodeResult of result.results) {
|
|
1113
|
+
try {
|
|
1114
|
+
const examples = this.db.prepare(`
|
|
1115
|
+
SELECT
|
|
1116
|
+
parameters_json,
|
|
1117
|
+
template_name,
|
|
1118
|
+
template_views
|
|
1119
|
+
FROM template_node_configs
|
|
1120
|
+
WHERE node_type = ?
|
|
1121
|
+
ORDER BY rank
|
|
1122
|
+
LIMIT 2
|
|
1123
|
+
`).all(nodeResult.workflowNodeType);
|
|
1124
|
+
if (examples.length > 0) {
|
|
1125
|
+
nodeResult.examples = examples.map((ex) => ({
|
|
1126
|
+
configuration: JSON.parse(ex.parameters_json),
|
|
1127
|
+
template: ex.template_name,
|
|
1128
|
+
views: ex.template_views
|
|
1129
|
+
}));
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
catch (error) {
|
|
1133
|
+
logger_1.logger.warn(`Failed to fetch examples for ${nodeResult.nodeType}:`, error.message);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return result;
|
|
1086
1138
|
}
|
|
1087
1139
|
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
|
1088
1140
|
if (words.length === 0) {
|
|
@@ -1097,7 +1149,7 @@ class N8NDocumentationMCPServer {
|
|
|
1097
1149
|
LIMIT ?
|
|
1098
1150
|
`).all(...params);
|
|
1099
1151
|
const rankedNodes = this.rankSearchResults(nodes, query, limit);
|
|
1100
|
-
|
|
1152
|
+
const result = {
|
|
1101
1153
|
query,
|
|
1102
1154
|
results: rankedNodes.map(node => ({
|
|
1103
1155
|
nodeType: node.node_type,
|
|
@@ -1109,6 +1161,33 @@ class N8NDocumentationMCPServer {
|
|
|
1109
1161
|
})),
|
|
1110
1162
|
totalCount: rankedNodes.length
|
|
1111
1163
|
};
|
|
1164
|
+
if (options?.includeExamples) {
|
|
1165
|
+
for (const nodeResult of result.results) {
|
|
1166
|
+
try {
|
|
1167
|
+
const examples = this.db.prepare(`
|
|
1168
|
+
SELECT
|
|
1169
|
+
parameters_json,
|
|
1170
|
+
template_name,
|
|
1171
|
+
template_views
|
|
1172
|
+
FROM template_node_configs
|
|
1173
|
+
WHERE node_type = ?
|
|
1174
|
+
ORDER BY rank
|
|
1175
|
+
LIMIT 2
|
|
1176
|
+
`).all(nodeResult.workflowNodeType);
|
|
1177
|
+
if (examples.length > 0) {
|
|
1178
|
+
nodeResult.examples = examples.map((ex) => ({
|
|
1179
|
+
configuration: JSON.parse(ex.parameters_json),
|
|
1180
|
+
template: ex.template_name,
|
|
1181
|
+
views: ex.template_views
|
|
1182
|
+
}));
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
catch (error) {
|
|
1186
|
+
logger_1.logger.warn(`Failed to fetch examples for ${nodeResult.nodeType}:`, error.message);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return result;
|
|
1112
1191
|
}
|
|
1113
1192
|
calculateRelevance(node, query) {
|
|
1114
1193
|
const lowerQuery = query.toLowerCase();
|
|
@@ -1363,11 +1442,11 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|
|
1363
1442
|
})),
|
|
1364
1443
|
};
|
|
1365
1444
|
}
|
|
1366
|
-
async getNodeEssentials(nodeType) {
|
|
1445
|
+
async getNodeEssentials(nodeType, includeExamples) {
|
|
1367
1446
|
await this.ensureInitialized();
|
|
1368
1447
|
if (!this.repository)
|
|
1369
1448
|
throw new Error('Repository not initialized');
|
|
1370
|
-
const cacheKey = `essentials:${nodeType}`;
|
|
1449
|
+
const cacheKey = `essentials:${nodeType}:${includeExamples ? 'withExamples' : 'basic'}`;
|
|
1371
1450
|
const cached = this.cache.get(cacheKey);
|
|
1372
1451
|
if (cached)
|
|
1373
1452
|
return cached;
|
|
@@ -1418,6 +1497,50 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|
|
1418
1497
|
developmentStyle: node.developmentStyle ?? 'programmatic'
|
|
1419
1498
|
}
|
|
1420
1499
|
};
|
|
1500
|
+
if (includeExamples) {
|
|
1501
|
+
try {
|
|
1502
|
+
const fullNodeType = (0, node_utils_1.getWorkflowNodeType)(node.package ?? 'n8n-nodes-base', node.nodeType);
|
|
1503
|
+
const examples = this.db.prepare(`
|
|
1504
|
+
SELECT
|
|
1505
|
+
parameters_json,
|
|
1506
|
+
template_name,
|
|
1507
|
+
template_views,
|
|
1508
|
+
complexity,
|
|
1509
|
+
use_cases,
|
|
1510
|
+
has_credentials,
|
|
1511
|
+
has_expressions
|
|
1512
|
+
FROM template_node_configs
|
|
1513
|
+
WHERE node_type = ?
|
|
1514
|
+
ORDER BY rank
|
|
1515
|
+
LIMIT 3
|
|
1516
|
+
`).all(fullNodeType);
|
|
1517
|
+
if (examples.length > 0) {
|
|
1518
|
+
result.examples = examples.map((ex) => ({
|
|
1519
|
+
configuration: JSON.parse(ex.parameters_json),
|
|
1520
|
+
source: {
|
|
1521
|
+
template: ex.template_name,
|
|
1522
|
+
views: ex.template_views,
|
|
1523
|
+
complexity: ex.complexity
|
|
1524
|
+
},
|
|
1525
|
+
useCases: ex.use_cases ? JSON.parse(ex.use_cases).slice(0, 2) : [],
|
|
1526
|
+
metadata: {
|
|
1527
|
+
hasCredentials: ex.has_credentials === 1,
|
|
1528
|
+
hasExpressions: ex.has_expressions === 1
|
|
1529
|
+
}
|
|
1530
|
+
}));
|
|
1531
|
+
result.examplesCount = examples.length;
|
|
1532
|
+
}
|
|
1533
|
+
else {
|
|
1534
|
+
result.examples = [];
|
|
1535
|
+
result.examplesCount = 0;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
catch (error) {
|
|
1539
|
+
logger_1.logger.warn(`Failed to fetch examples for ${nodeType}:`, error.message);
|
|
1540
|
+
result.examples = [];
|
|
1541
|
+
result.examplesCount = 0;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1421
1544
|
this.cache.set(cacheKey, result, 3600);
|
|
1422
1545
|
return result;
|
|
1423
1546
|
}
|
|
@@ -1463,37 +1586,6 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|
|
1463
1586
|
searchedIn: allProperties.length + ' properties'
|
|
1464
1587
|
};
|
|
1465
1588
|
}
|
|
1466
|
-
async getNodeForTask(task) {
|
|
1467
|
-
const template = task_templates_1.TaskTemplates.getTaskTemplate(task);
|
|
1468
|
-
if (!template) {
|
|
1469
|
-
const similar = task_templates_1.TaskTemplates.searchTasks(task);
|
|
1470
|
-
throw new Error(`Unknown task: ${task}. ` +
|
|
1471
|
-
(similar.length > 0
|
|
1472
|
-
? `Did you mean: ${similar.slice(0, 3).join(', ')}?`
|
|
1473
|
-
: `Use 'list_tasks' to see available tasks.`));
|
|
1474
|
-
}
|
|
1475
|
-
return {
|
|
1476
|
-
task: template.task,
|
|
1477
|
-
description: template.description,
|
|
1478
|
-
nodeType: template.nodeType,
|
|
1479
|
-
configuration: template.configuration,
|
|
1480
|
-
userMustProvide: template.userMustProvide,
|
|
1481
|
-
optionalEnhancements: template.optionalEnhancements || [],
|
|
1482
|
-
notes: template.notes || [],
|
|
1483
|
-
example: {
|
|
1484
|
-
node: {
|
|
1485
|
-
type: template.nodeType,
|
|
1486
|
-
parameters: template.configuration
|
|
1487
|
-
},
|
|
1488
|
-
userInputsNeeded: template.userMustProvide.map(p => ({
|
|
1489
|
-
property: p.property,
|
|
1490
|
-
currentValue: this.getPropertyValue(template.configuration, p.property),
|
|
1491
|
-
description: p.description,
|
|
1492
|
-
example: p.example
|
|
1493
|
-
}))
|
|
1494
|
-
}
|
|
1495
|
-
};
|
|
1496
|
-
}
|
|
1497
1589
|
getPropertyValue(config, path) {
|
|
1498
1590
|
const parts = path.split('.');
|
|
1499
1591
|
let value = config;
|