mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-04-02 07:33:07 +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:
@@ -26,6 +26,7 @@ import {
|
||||
} from './utils/protocol-version';
|
||||
import { InstanceContext, validateInstanceContext } from './types/instance-context';
|
||||
import { SessionState } from './types/session-state';
|
||||
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||
import { closeSharedDatabase } from './database/shared-database';
|
||||
|
||||
dotenv.config();
|
||||
@@ -97,6 +98,10 @@ function logSecurityEvent(
|
||||
logger.info(`[SECURITY] ${event}`, logEntry);
|
||||
}
|
||||
|
||||
export interface SingleSessionHTTPServerOptions {
|
||||
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||
}
|
||||
|
||||
export class SingleSessionHTTPServer {
|
||||
// Map to store transports by session ID (following SDK pattern)
|
||||
private transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
|
||||
@@ -114,8 +119,10 @@ export class SingleSessionHTTPServer {
|
||||
) * 60 * 1000;
|
||||
private authToken: string | null = null;
|
||||
private cleanupTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
constructor() {
|
||||
private generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||
|
||||
constructor(options?: SingleSessionHTTPServerOptions) {
|
||||
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||
// Validate environment on construction
|
||||
this.validateEnvironment();
|
||||
// No longer pre-create session - will be created per initialize request following SDK pattern
|
||||
@@ -565,8 +572,10 @@ export class SingleSessionHTTPServer {
|
||||
sessionIdToUse = sessionId || uuidv4();
|
||||
}
|
||||
|
||||
const server = new N8NDocumentationMCPServer(instanceContext);
|
||||
|
||||
const server = new N8NDocumentationMCPServer(instanceContext, undefined, {
|
||||
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||
});
|
||||
|
||||
transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: () => sessionIdToUse,
|
||||
onsessioninitialized: (initializedSessionId: string) => {
|
||||
@@ -772,7 +781,9 @@ export class SingleSessionHTTPServer {
|
||||
try {
|
||||
// Create new session
|
||||
logger.info('Creating new N8NDocumentationMCPServer for SSE...');
|
||||
const server = new N8NDocumentationMCPServer();
|
||||
const server = new N8NDocumentationMCPServer(undefined, undefined, {
|
||||
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||
});
|
||||
|
||||
// Generate cryptographically secure session ID
|
||||
const sessionId = uuidv4();
|
||||
|
||||
@@ -21,6 +21,12 @@ export {
|
||||
export type {
|
||||
SessionState
|
||||
} from './types/session-state';
|
||||
export type {
|
||||
GenerateWorkflowArgs,
|
||||
GenerateWorkflowResult,
|
||||
GenerateWorkflowHandler,
|
||||
GenerateWorkflowHelpers
|
||||
} from './types/generate-workflow';
|
||||
|
||||
// UI module exports
|
||||
export type { UIAppConfig, UIMetadata } from './mcp/ui/types';
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SingleSessionHTTPServer } from './http-server-single-session';
|
||||
import { logger } from './utils/logger';
|
||||
import { InstanceContext } from './types/instance-context';
|
||||
import { SessionState } from './types/session-state';
|
||||
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||
|
||||
export interface EngineHealth {
|
||||
status: 'healthy' | 'unhealthy';
|
||||
@@ -26,6 +27,7 @@ export interface EngineHealth {
|
||||
export interface EngineOptions {
|
||||
sessionTimeout?: number;
|
||||
logLevel?: 'error' | 'warn' | 'info' | 'debug';
|
||||
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||
}
|
||||
|
||||
export class N8NMCPEngine {
|
||||
@@ -33,9 +35,11 @@ export class N8NMCPEngine {
|
||||
private startTime: Date;
|
||||
|
||||
constructor(options: EngineOptions = {}) {
|
||||
this.server = new SingleSessionHTTPServer();
|
||||
this.server = new SingleSessionHTTPServer({
|
||||
generateWorkflowHandler: options.generateWorkflowHandler,
|
||||
});
|
||||
this.startTime = new Date();
|
||||
|
||||
|
||||
if (options.logLevel) {
|
||||
process.env.LOG_LEVEL = options.logLevel;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
STANDARD_PROTOCOL_VERSION
|
||||
} from '../utils/protocol-version';
|
||||
import { InstanceContext } from '../types/instance-context';
|
||||
import { GenerateWorkflowHandler, GenerateWorkflowHelpers } from '../types/generate-workflow';
|
||||
import { telemetry } from '../telemetry';
|
||||
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
|
||||
import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints';
|
||||
@@ -141,6 +142,10 @@ interface VersionComparisonInfo {
|
||||
|
||||
type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo;
|
||||
|
||||
interface MCPServerOptions {
|
||||
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||
}
|
||||
|
||||
export class N8NDocumentationMCPServer {
|
||||
private server: Server;
|
||||
private db: DatabaseAdapter | null = null;
|
||||
@@ -157,10 +162,12 @@ export class N8NDocumentationMCPServer {
|
||||
private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup
|
||||
private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release
|
||||
private isShutdown: boolean = false; // Prevent double-shutdown
|
||||
private generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||
|
||||
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger) {
|
||||
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger, options?: MCPServerOptions) {
|
||||
this.instanceContext = instanceContext;
|
||||
this.earlyLogger = earlyLogger || null;
|
||||
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||
// Check for test environment first
|
||||
const envDbPath = process.env.NODE_DB_PATH;
|
||||
let dbPath: string | null = null;
|
||||
@@ -1531,6 +1538,57 @@ export class N8NDocumentationMCPServer {
|
||||
}
|
||||
}
|
||||
|
||||
case 'n8n_generate_workflow': {
|
||||
this.validateToolParams(name, args, ['description']);
|
||||
|
||||
if (this.generateWorkflowHandler && this.instanceContext) {
|
||||
await this.ensureInitialized();
|
||||
if (!this.repository) {
|
||||
throw new Error('Repository not initialized');
|
||||
}
|
||||
|
||||
const repo = this.repository;
|
||||
const ctx = this.instanceContext;
|
||||
const helpers: GenerateWorkflowHelpers = {
|
||||
createWorkflow: (wfArgs) =>
|
||||
n8nHandlers.handleCreateWorkflow(wfArgs, ctx),
|
||||
validateWorkflow: (id) =>
|
||||
n8nHandlers.handleValidateWorkflow({ id }, repo, ctx),
|
||||
autofixWorkflow: (id) =>
|
||||
n8nHandlers.handleAutofixWorkflow({ id }, repo, ctx),
|
||||
getWorkflow: (id) =>
|
||||
n8nHandlers.handleGetWorkflow({ id }, ctx),
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await this.generateWorkflowHandler(
|
||||
{ description: args.description, skip_cache: args.skip_cache },
|
||||
ctx,
|
||||
helpers
|
||||
);
|
||||
return result ?? { success: false, error: 'Handler returned no result' };
|
||||
} catch (err: any) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
return { success: false, error: message };
|
||||
}
|
||||
}
|
||||
|
||||
// No handler and/or no instanceContext — self-hosted deployment
|
||||
return {
|
||||
hosted_only: true,
|
||||
message: 'The n8n_generate_workflow tool is available exclusively on the hosted version of n8n-mcp. ' +
|
||||
'It uses AI to generate complete, validated n8n workflows from natural language descriptions.\n\n' +
|
||||
'To access this feature:\n' +
|
||||
'1. Register for free at https://dashboard.n8n-mcp.com\n' +
|
||||
'2. Connect your n8n instance\n' +
|
||||
'3. Use your hosted API key in your MCP client\n\n' +
|
||||
'The hosted service includes:\n' +
|
||||
'- 73,000+ pre-built workflow templates with instant deployment\n' +
|
||||
'- AI-powered fresh generation for custom workflows\n' +
|
||||
'- Automatic validation and error correction'
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
n8nExecutionsDoc,
|
||||
n8nWorkflowVersionsDoc,
|
||||
n8nDeployTemplateDoc,
|
||||
n8nManageDatatableDoc
|
||||
n8nManageDatatableDoc,
|
||||
n8nGenerateWorkflowDoc
|
||||
} from './workflow_management';
|
||||
|
||||
// Combine all tool documentations into a single object
|
||||
@@ -62,7 +63,8 @@ export const toolsDocumentation: Record<string, ToolDocumentation> = {
|
||||
n8n_executions: n8nExecutionsDoc,
|
||||
n8n_workflow_versions: n8nWorkflowVersionsDoc,
|
||||
n8n_deploy_template: n8nDeployTemplateDoc,
|
||||
n8n_manage_datatable: n8nManageDatatableDoc
|
||||
n8n_manage_datatable: n8nManageDatatableDoc,
|
||||
n8n_generate_workflow: n8nGenerateWorkflowDoc
|
||||
};
|
||||
|
||||
// Re-export types
|
||||
|
||||
@@ -11,3 +11,4 @@ export { n8nExecutionsDoc } from './n8n-executions';
|
||||
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
|
||||
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
|
||||
export { n8nManageDatatableDoc } from './n8n-manage-datatable';
|
||||
export { n8nGenerateWorkflowDoc } from './n8n-generate-workflow';
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { ToolDocumentation } from '../types';
|
||||
|
||||
export const n8nGenerateWorkflowDoc: ToolDocumentation = {
|
||||
name: 'n8n_generate_workflow',
|
||||
category: 'workflow_management',
|
||||
essentials: {
|
||||
description: 'Generate an n8n workflow from a natural language description using AI. Creates and deploys a ready-to-use workflow to your n8n instance.',
|
||||
keyParameters: ['description', 'skip_cache'],
|
||||
example: 'n8n_generate_workflow({description: "Send a Slack message every morning at 9am"})',
|
||||
performance: 'Network-dependent (2-15s depending on cache hit vs fresh generation)',
|
||||
tips: [
|
||||
'Include trigger type (webhook, schedule, manual) in the description',
|
||||
'Mention specific services to integrate (Slack, Gmail, Google Sheets, etc.)',
|
||||
'Use skip_cache=true to force fresh AI generation instead of cached templates',
|
||||
'Available exclusively on the hosted version of n8n-mcp'
|
||||
]
|
||||
},
|
||||
full: {
|
||||
description: 'Generates an n8n workflow from a natural language description using AI. On the hosted service, this tool first searches a cache of 73,000+ pre-built workflows for a match, and falls back to AI-powered fresh generation for custom workflows. Generated workflows are automatically validated and error-corrected before deployment. On self-hosted instances, this tool returns a message directing users to the hosted service.',
|
||||
parameters: {
|
||||
description: { type: 'string', required: true, description: 'Clear description of what the workflow should do. Include: trigger type (webhook, schedule, manual), services to integrate (Slack, Gmail, etc.), and the logic/flow.' },
|
||||
skip_cache: { type: 'boolean', description: 'Set to true to bypass the workflow cache and force fresh AI generation. Default: false (uses cached workflows when a good match exists).' }
|
||||
},
|
||||
returns: 'Object with success, source (cache/generated), workflow_id, workflow_name, workflow_url, node_count, node_summary, and message. On self-hosted instances, returns hosted_only: true with information about the hosted service.',
|
||||
examples: [
|
||||
`// Generate a simple scheduled workflow
|
||||
n8n_generate_workflow({
|
||||
description: "Send a Slack message every morning at 9am with a daily standup reminder"
|
||||
})`,
|
||||
`// Generate with specific services
|
||||
n8n_generate_workflow({
|
||||
description: "When a new row is added to Google Sheets, create a task in Notion and notify via email"
|
||||
})`,
|
||||
`// Force fresh generation (skip cache)
|
||||
n8n_generate_workflow({
|
||||
description: "Webhook that receives JSON data, transforms it, and posts to a REST API",
|
||||
skip_cache: true
|
||||
})`
|
||||
],
|
||||
useCases: [
|
||||
'Quickly create workflows from natural language descriptions',
|
||||
'Generate complex multi-service integrations',
|
||||
'Bootstrap automation projects with AI-generated workflows',
|
||||
'Create workflows without deep knowledge of n8n node configuration'
|
||||
],
|
||||
performance: 'Cache hit: ~2s. Fresh generation: 5-15s. Both within typical MCP client timeout.',
|
||||
bestPractices: [
|
||||
'Be specific about trigger type and services in the description',
|
||||
'Review generated workflows before activating',
|
||||
'Use n8n_validate_workflow to check the generated workflow',
|
||||
'Configure credentials in n8n UI before activating',
|
||||
'Use skip_cache only when cached results do not match your needs'
|
||||
],
|
||||
pitfalls: [
|
||||
'**Hosted-only feature** — self-hosted instances receive a redirect message',
|
||||
'Generated workflows are created in INACTIVE state',
|
||||
'Credentials must be configured manually in the n8n UI',
|
||||
'Complex workflows may need manual adjustments after generation'
|
||||
],
|
||||
relatedTools: ['n8n_create_workflow', 'n8n_deploy_template', 'n8n_validate_workflow', 'n8n_autofix_workflow', 'search_templates']
|
||||
}
|
||||
};
|
||||
@@ -102,7 +102,7 @@ When working with Code nodes, always start by calling the relevant guide:
|
||||
- validate_node({nodeType: "nodes-base.slack", config: {...}}) - Full validation with errors/warnings/suggestions
|
||||
- validate_workflow({workflow: {...}}) - Validate entire workflow
|
||||
|
||||
## Tool Categories (19 Tools Total)
|
||||
## Tool Categories (21 Tools Total)
|
||||
|
||||
**Discovery Tools** (1 tool)
|
||||
- search_nodes - Full-text search across all nodes (supports OR, AND, FUZZY modes)
|
||||
@@ -127,7 +127,7 @@ When working with Code nodes, always start by calling the relevant guide:
|
||||
- searchMode='by_metadata': Filter by complexity/services
|
||||
- searchMode='patterns': Workflow pattern summaries from 2,700+ templates
|
||||
|
||||
**n8n API Tools** (13 tools, requires N8N_API_URL configuration)
|
||||
**n8n API Tools** (15 tools, requires N8N_API_URL configuration)
|
||||
- n8n_create_workflow - Create new workflows
|
||||
- n8n_get_workflow - Get workflow with mode='full'/'details'/'structure'/'minimal'
|
||||
- n8n_update_full_workflow - Full workflow replacement
|
||||
@@ -141,6 +141,8 @@ When working with Code nodes, always start by calling the relevant guide:
|
||||
- n8n_health_check - Check n8n API connectivity
|
||||
- n8n_workflow_versions - Version history and rollback
|
||||
- n8n_deploy_template - Deploy templates directly to n8n instance
|
||||
- n8n_manage_datatable - Manage data tables and rows
|
||||
- n8n_generate_workflow - Generate workflow from natural language description
|
||||
|
||||
## Performance Characteristics
|
||||
- Instant (<10ms): search_nodes, get_node (minimal/standard)
|
||||
|
||||
@@ -654,4 +654,34 @@ export const n8nManagementTools: ToolDefinition[] = [
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'n8n_generate_workflow',
|
||||
description: 'Generate an n8n workflow from a natural language description using AI. ' +
|
||||
'Describe what the workflow should do (trigger type, services, logic) and this tool ' +
|
||||
'will create and deploy a ready-to-use workflow to your n8n instance. ' +
|
||||
'Set skip_cache=true to force fresh generation instead of using pre-built templates.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Clear description of what the workflow should do. Include: trigger type ' +
|
||||
'(webhook, schedule, manual), services to integrate (Slack, Gmail, etc.), and the logic/flow.'
|
||||
},
|
||||
skip_cache: {
|
||||
type: 'boolean',
|
||||
description: 'Set to true to bypass the workflow cache and force fresh AI generation. ' +
|
||||
'Default: false (uses cached workflows when a good match exists).'
|
||||
}
|
||||
},
|
||||
required: ['description'],
|
||||
},
|
||||
annotations: {
|
||||
title: 'Generate Workflow',
|
||||
readOnlyHint: false,
|
||||
destructiveHint: false,
|
||||
idempotentHint: false,
|
||||
openWorldHint: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
32
src/types/generate-workflow.ts
Normal file
32
src/types/generate-workflow.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { InstanceContext } from './instance-context';
|
||||
|
||||
export interface GenerateWorkflowArgs {
|
||||
description: string;
|
||||
skip_cache?: boolean;
|
||||
}
|
||||
|
||||
export interface GenerateWorkflowResult {
|
||||
success: boolean;
|
||||
source?: 'cache' | 'generated';
|
||||
workflow_id?: string;
|
||||
workflow_name?: string;
|
||||
workflow_url?: string;
|
||||
node_count?: number;
|
||||
node_summary?: string;
|
||||
trigger_type?: string;
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export type GenerateWorkflowHandler = (
|
||||
args: GenerateWorkflowArgs,
|
||||
context: InstanceContext,
|
||||
helpers: GenerateWorkflowHelpers
|
||||
) => Promise<GenerateWorkflowResult>;
|
||||
|
||||
export interface GenerateWorkflowHelpers {
|
||||
createWorkflow(args: { name: string; nodes: any[]; connections: any }): Promise<any>;
|
||||
validateWorkflow(workflowId: string): Promise<any>;
|
||||
autofixWorkflow(workflowId: string): Promise<any>;
|
||||
getWorkflow(workflowId: string): Promise<any>;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ export * from './node-types';
|
||||
export * from './type-structures';
|
||||
export * from './instance-context';
|
||||
export * from './session-state';
|
||||
export * from './generate-workflow';
|
||||
|
||||
export interface MCPServerConfig {
|
||||
port: number;
|
||||
|
||||
Reference in New Issue
Block a user