mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-04-01 07:03:08 +00:00
feat: add n8n_generate_workflow tool for hosted workflow generation
Add new MCP tool that enables AI-powered workflow generation from natural language descriptions. Uses handler delegation pattern — hosting environments inject a GenerateWorkflowHandler via EngineOptions, self-hosted instances receive a hosted-only informational response. Handler flows through N8NMCPEngine → SingleSessionHTTPServer → N8NDocumentationMCPServer with helpers for createWorkflow, validateWorkflow, autofixWorkflow, and getWorkflow. Includes full tool documentation, tests, and corrected tools overview count. Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
25
dist/services/expression-validator.js
vendored
25
dist/services/expression-validator.js
vendored
@@ -134,6 +134,20 @@ class ExpressionValidator {
|
||||
combinedResult.valid = combinedResult.errors.length === 0;
|
||||
return combinedResult;
|
||||
}
|
||||
static checkBareExpression(value, path, result) {
|
||||
if (value.includes('{{') || value.startsWith('=')) {
|
||||
return;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
for (const { pattern, name } of this.BARE_EXPRESSION_PATTERNS) {
|
||||
if (pattern.test(trimmed)) {
|
||||
result.warnings.push((path ? `${path}: ` : '') +
|
||||
`Possible unwrapped expression: "${trimmed}" looks like an n8n ${name} reference. ` +
|
||||
`Use "={{ ${trimmed} }}" to evaluate it as an expression.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
static validateParametersRecursive(obj, context, result, path = '', visited = new WeakSet()) {
|
||||
if (obj && typeof obj === 'object') {
|
||||
if (visited.has(obj)) {
|
||||
@@ -142,6 +156,7 @@ class ExpressionValidator {
|
||||
visited.add(obj);
|
||||
}
|
||||
if (typeof obj === 'string') {
|
||||
this.checkBareExpression(obj, path, result);
|
||||
if (obj.includes('{{')) {
|
||||
const validation = this.validateExpression(obj, context);
|
||||
validation.errors.forEach(error => {
|
||||
@@ -168,6 +183,16 @@ class ExpressionValidator {
|
||||
}
|
||||
}
|
||||
exports.ExpressionValidator = ExpressionValidator;
|
||||
ExpressionValidator.BARE_EXPRESSION_PATTERNS = [
|
||||
{ pattern: /^\$json[.\[]/, name: '$json' },
|
||||
{ pattern: /^\$node\[/, name: '$node' },
|
||||
{ pattern: /^\$input\./, name: '$input' },
|
||||
{ pattern: /^\$execution\./, name: '$execution' },
|
||||
{ pattern: /^\$workflow\./, name: '$workflow' },
|
||||
{ pattern: /^\$prevNode\./, name: '$prevNode' },
|
||||
{ pattern: /^\$env\./, name: '$env' },
|
||||
{ pattern: /^\$(now|today|itemIndex|runIndex)$/, name: 'built-in variable' },
|
||||
];
|
||||
ExpressionValidator.EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g;
|
||||
ExpressionValidator.VARIABLE_PATTERNS = {
|
||||
json: /\$json(\.[a-zA-Z_][\w]*|\["[^"]+"\]|\['[^']+'\]|\[\d+\])*/g,
|
||||
|
||||
Reference in New Issue
Block a user