Compare commits

..

1 Commits

Author SHA1 Message Date
czlonkowski
b800ff0cd9 feat: add multi-step flow to n8n_generate_workflow tool (v2.44.0)
Enable AI agents to act as quality gates for workflow generation:
proposals → review → deploy. New parameters: deploy_id, confirm_deploy.
New types: GenerateWorkflowProposal, status field on result.

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 00:17:27 +02:00
18 changed files with 180 additions and 48 deletions

View File

@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [2.44.0] - 2026-04-01
### Added
- **Multi-step workflow generation flow**: `n8n_generate_workflow` now supports a three-step flow where AI agents act as quality gates — get proposals, review, then deploy. New parameters: `deploy_id` (deploy a specific proposal), `confirm_deploy` (deploy a previously generated preview).
- **`GenerateWorkflowProposal` type**: New exported type for workflow proposals with `id`, `name`, `description`, `flow_summary`, and `credentials_needed` fields.
- **`status` field on `GenerateWorkflowResult`**: Indicates the current phase — `proposals`, `preview`, `deployed`, or `error`.
### Changed
- **Tool description updated**: `n8n_generate_workflow` description now explains the multi-step flow instead of auto-deploy behavior.
- **Tool documentation updated**: Essentials and full docs reflect the three-step flow with examples for each step.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.43.0] - 2026-03-31 ## [2.43.0] - 2026-03-31
### Added ### Added

2
dist/index.d.ts vendored
View File

@@ -5,7 +5,7 @@ export { N8NDocumentationMCPServer } from './mcp/server';
export type { InstanceContext } from './types/instance-context'; export type { InstanceContext } from './types/instance-context';
export { validateInstanceContext, isInstanceContext } from './types/instance-context'; export { validateInstanceContext, isInstanceContext } from './types/instance-context';
export type { SessionState } from './types/session-state'; export type { SessionState } from './types/session-state';
export type { GenerateWorkflowArgs, GenerateWorkflowResult, GenerateWorkflowHandler, GenerateWorkflowHelpers } from './types/generate-workflow'; export type { GenerateWorkflowArgs, GenerateWorkflowResult, GenerateWorkflowProposal, GenerateWorkflowHandler, GenerateWorkflowHelpers } from './types/generate-workflow';
export type { UIAppConfig, UIMetadata } from './mcp/ui/types'; export type { UIAppConfig, UIMetadata } from './mcp/ui/types';
export { UI_APP_CONFIGS } from './mcp/ui/app-configs'; export { UI_APP_CONFIGS } from './mcp/ui/app-configs';
export type { Tool, CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js'; export type { Tool, CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';

2
dist/index.d.ts.map vendored
View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,YAAY,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,YAAY,EACV,IAAI,EACJ,cAAc,EACd,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,YAAY,MAAM,cAAc,CAAC;AACxC,eAAe,YAAY,CAAC"} {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,YAAY,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,YAAY,EACV,IAAI,EACJ,cAAc,EACd,eAAe,EAChB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,YAAY,MAAM,cAAc,CAAC;AACxC,eAAe,YAAY,CAAC"}

2
dist/index.js.map vendored
View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAOA,2CAAyE;AAAhE,0GAAA,YAAY,OAAA;AACrB,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAChC,2DAAyD;AAAhD,iHAAA,cAAc,OAAA;AACvB,uCAAyD;AAAhD,mHAAA,yBAAyB,OAAA;AAMlC,6DAGkC;AAFhC,2HAAA,uBAAuB,OAAA;AACvB,qHAAA,iBAAiB,OAAA;AAcnB,oDAAsD;AAA7C,6GAAA,cAAc,OAAA;AAUvB,8DAAwC;AACxC,kBAAe,oBAAY,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAOA,2CAAyE;AAAhE,0GAAA,YAAY,OAAA;AACrB,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAChC,2DAAyD;AAAhD,iHAAA,cAAc,OAAA;AACvB,uCAAyD;AAAhD,mHAAA,yBAAyB,OAAA;AAMlC,6DAGkC;AAFhC,2HAAA,uBAAuB,OAAA;AACvB,qHAAA,iBAAiB,OAAA;AAenB,oDAAsD;AAA7C,6GAAA,cAAc,OAAA;AAUvB,8DAAwC;AACxC,kBAAe,oBAAY,CAAC"}

View File

@@ -1 +1 @@
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"} {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}

2
dist/mcp/server.js vendored
View File

@@ -1156,7 +1156,7 @@ class N8NDocumentationMCPServer {
getWorkflow: (id) => n8nHandlers.handleGetWorkflow({ id }, ctx), getWorkflow: (id) => n8nHandlers.handleGetWorkflow({ id }, ctx),
}; };
try { try {
const result = await this.generateWorkflowHandler({ description: args.description, skip_cache: args.skip_cache }, ctx, helpers); const result = await this.generateWorkflowHandler(args, ctx, helpers);
return result ?? { success: false, error: 'Handler returned no result' }; return result ?? { success: false, error: 'Handler returned no result' };
} }
catch (err) { catch (err) {

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"tools-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-n8n-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,cAAc,EAsqB9C,CAAC"} {"version":3,"file":"tools-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-n8n-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,kBAAkB,EAAE,cAAc,EAgrB9C,CAAC"}

View File

@@ -638,9 +638,10 @@ exports.n8nManagementTools = [
{ {
name: 'n8n_generate_workflow', name: 'n8n_generate_workflow',
description: 'Generate an n8n workflow from a natural language description using AI. ' + 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 ' + 'Call with just a description to get workflow proposals. ' +
'will create and deploy a ready-to-use workflow to your n8n instance. ' + 'Then call again with deploy_id to deploy a chosen proposal, ' +
'Set skip_cache=true to force fresh generation instead of using pre-built templates.', 'or set skip_cache=true to generate a fresh workflow. ' +
'Use confirm_deploy=true to deploy a previously generated workflow.',
inputSchema: { inputSchema: {
type: 'object', type: 'object',
properties: { properties: {
@@ -651,8 +652,17 @@ exports.n8nManagementTools = [
}, },
skip_cache: { skip_cache: {
type: 'boolean', type: 'boolean',
description: 'Set to true to bypass the workflow cache and force fresh AI generation. ' + description: 'Set to true to skip proposals and generate a fresh workflow from scratch. ' +
'Default: false (uses cached workflows when a good match exists).' 'Returns a preview — call again with confirm_deploy=true to deploy it.'
},
deploy_id: {
type: 'string',
description: 'ID of a proposal to deploy. Get proposal IDs from a previous call ' +
'that returned status "proposals".'
},
confirm_deploy: {
type: 'boolean',
description: 'Set to true to deploy the workflow from the last generation preview.'
} }
}, },
required: ['description'], required: ['description'],

File diff suppressed because one or more lines are too long

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "n8n-mcp", "name": "n8n-mcp",
"version": "2.43.0", "version": "2.44.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "n8n-mcp", "name": "n8n-mcp",
"version": "2.43.0", "version": "2.44.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "1.28.0", "@modelcontextprotocol/sdk": "1.28.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "n8n-mcp", "name": "n8n-mcp",
"version": "2.43.0", "version": "2.44.0",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@@ -24,6 +24,7 @@ export type {
export type { export type {
GenerateWorkflowArgs, GenerateWorkflowArgs,
GenerateWorkflowResult, GenerateWorkflowResult,
GenerateWorkflowProposal,
GenerateWorkflowHandler, GenerateWorkflowHandler,
GenerateWorkflowHelpers GenerateWorkflowHelpers
} from './types/generate-workflow'; } from './types/generate-workflow';

View File

@@ -1561,11 +1561,7 @@ export class N8NDocumentationMCPServer {
}; };
try { try {
const result = await this.generateWorkflowHandler( const result = await this.generateWorkflowHandler(args, ctx, helpers);
{ description: args.description, skip_cache: args.skip_cache },
ctx,
helpers
);
return result ?? { success: false, error: 'Handler returned no result' }; return result ?? { success: false, error: 'Handler returned no result' };
} catch (err: any) { } catch (err: any) {
const message = err instanceof Error ? err.message : String(err); const message = err instanceof Error ? err.message : String(err);

View File

@@ -4,58 +4,84 @@ export const n8nGenerateWorkflowDoc: ToolDocumentation = {
name: 'n8n_generate_workflow', name: 'n8n_generate_workflow',
category: 'workflow_management', category: 'workflow_management',
essentials: { 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.', description: 'Generate workflows from natural language. Three-step flow:\n' +
keyParameters: ['description', 'skip_cache'], '1. Call with description → get proposals\n' +
'2. Call with deploy_id → deploy a proposal, OR skip_cache=true → fresh generation preview\n' +
'3. Call with confirm_deploy=true → deploy the preview',
keyParameters: ['description', 'skip_cache', 'deploy_id', 'confirm_deploy'],
example: 'n8n_generate_workflow({description: "Send a Slack message every morning at 9am"})', 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)', performance: 'Network-dependent (2-15s depending on cache hit vs fresh generation)',
tips: [ tips: [
'Include trigger type (webhook, schedule, manual) in the description', 'Include trigger type (webhook, schedule, manual) in the description',
'Mention specific services to integrate (Slack, Gmail, Google Sheets, etc.)', 'Mention specific services to integrate (Slack, Gmail, Google Sheets, etc.)',
'Use skip_cache=true to force fresh AI generation instead of cached templates', 'Review proposals before deploying — use deploy_id to pick one',
'Use skip_cache=true to generate fresh, then confirm_deploy=true to deploy',
'Available exclusively on the hosted version of n8n-mcp' 'Available exclusively on the hosted version of n8n-mcp'
] ]
}, },
full: { 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.', description: 'Generates n8n workflows from natural language using a multi-step flow. ' +
'Step 1: Call with description to get up to 5 proposals (not deployed). ' +
'Step 2a: Call with deploy_id to deploy a chosen proposal. ' +
'Step 2b: Call with skip_cache=true to generate a fresh workflow (returns preview, not deployed). ' +
'Step 3: Call with confirm_deploy=true to deploy the preview. ' +
'On self-hosted instances, returns a message directing users to the hosted service.',
parameters: { 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.' }, 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).' } skip_cache: { type: 'boolean', description: 'Set to true to skip proposals and generate a fresh workflow from scratch. Returns a preview — call again with confirm_deploy=true to deploy it.' },
deploy_id: { type: 'string', description: 'ID of a proposal to deploy. Get proposal IDs from a previous call that returned status "proposals".' },
confirm_deploy: { type: 'boolean', description: 'Set to true to deploy the workflow from the last generation preview.' }
}, },
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.', returns: 'Object with success, status (proposals/preview/deployed/error), and context-dependent fields. ' +
'For proposals: proposals[] with id, name, description, flow_summary, credentials_needed. ' +
'For preview: workflow structure details. ' +
'For deployed: workflow_id, workflow_name, workflow_url, node_count, node_summary. ' +
'On self-hosted instances, returns hosted_only: true.',
examples: [ examples: [
`// Generate a simple scheduled workflow `// Step 1: Get proposals
n8n_generate_workflow({ n8n_generate_workflow({
description: "Send a Slack message every morning at 9am with a daily standup reminder" description: "Send a Slack message every morning at 9am with a daily standup reminder"
})`, })
`// Generate with specific services // Returns: { status: "proposals", proposals: [{ id: "uuid-1", name: "...", ... }, ...] }`,
`// Step 2a: Deploy a chosen proposal
n8n_generate_workflow({ n8n_generate_workflow({
description: "When a new row is added to Google Sheets, create a task in Notion and notify via email" description: "Send a Slack message every morning at 9am",
})`, deploy_id: "uuid-1"
`// Force fresh generation (skip cache) })
// Returns: { status: "deployed", workflow_id: "123", ... }`,
`// Step 2b: Fresh generation (skip cache)
n8n_generate_workflow({ n8n_generate_workflow({
description: "Webhook that receives JSON data, transforms it, and posts to a REST API", description: "Webhook that receives JSON data, transforms it, and posts to a REST API",
skip_cache: true skip_cache: true
})` })
// Returns: { status: "preview", ... }`,
`// Step 3: Deploy the preview
n8n_generate_workflow({
description: "Webhook that receives JSON data, transforms it, and posts to a REST API",
confirm_deploy: true
})
// Returns: { status: "deployed", workflow_id: "456", ... }`
], ],
useCases: [ useCases: [
'Quickly create workflows from natural language descriptions', 'Quickly create workflows from natural language descriptions',
'Generate complex multi-service integrations', 'Review proposals before deploying to maintain quality',
'Bootstrap automation projects with AI-generated workflows', 'Generate complex multi-service integrations with agent oversight',
'Create workflows without deep knowledge of n8n node configuration' 'Create workflows without deep knowledge of n8n node configuration'
], ],
performance: 'Cache hit: ~2s. Fresh generation: 5-15s. Both within typical MCP client timeout.', performance: 'Proposals: ~2s. Fresh generation: 5-15s. Deploy: ~3s. All within typical MCP client timeout.',
bestPractices: [ bestPractices: [
'Be specific about trigger type and services in the description', 'Be specific about trigger type and services in the description',
'Review generated workflows before activating', 'Review proposals before deploying — pick the best match with deploy_id',
'Use n8n_validate_workflow to check the generated workflow', 'Use skip_cache only when proposals do not match your needs',
'Configure credentials in n8n UI before activating', 'After deployment, use n8n_validate_workflow to verify the result',
'Use skip_cache only when cached results do not match your needs' 'Configure credentials in n8n UI before activating'
], ],
pitfalls: [ pitfalls: [
'**Hosted-only feature** — self-hosted instances receive a redirect message', '**Hosted-only feature** — self-hosted instances receive a redirect message',
'Proposals are NOT deployed — you must call again with deploy_id or confirm_deploy',
'Generated workflows are created in INACTIVE state', 'Generated workflows are created in INACTIVE state',
'Credentials must be configured manually in the n8n UI', 'Credentials must be configured manually in the n8n UI',
'Complex workflows may need manual adjustments after generation' 'Session state for pending proposals/preview is per MCP session'
], ],
relatedTools: ['n8n_create_workflow', 'n8n_deploy_template', 'n8n_validate_workflow', 'n8n_autofix_workflow', 'search_templates'] relatedTools: ['n8n_create_workflow', 'n8n_deploy_template', 'n8n_validate_workflow', 'n8n_autofix_workflow', 'search_templates']
} }

View File

@@ -657,9 +657,10 @@ export const n8nManagementTools: ToolDefinition[] = [
{ {
name: 'n8n_generate_workflow', name: 'n8n_generate_workflow',
description: 'Generate an n8n workflow from a natural language description using AI. ' + 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 ' + 'Call with just a description to get workflow proposals. ' +
'will create and deploy a ready-to-use workflow to your n8n instance. ' + 'Then call again with deploy_id to deploy a chosen proposal, ' +
'Set skip_cache=true to force fresh generation instead of using pre-built templates.', 'or set skip_cache=true to generate a fresh workflow. ' +
'Use confirm_deploy=true to deploy a previously generated workflow.',
inputSchema: { inputSchema: {
type: 'object', type: 'object',
properties: { properties: {
@@ -670,8 +671,17 @@ export const n8nManagementTools: ToolDefinition[] = [
}, },
skip_cache: { skip_cache: {
type: 'boolean', type: 'boolean',
description: 'Set to true to bypass the workflow cache and force fresh AI generation. ' + description: 'Set to true to skip proposals and generate a fresh workflow from scratch. ' +
'Default: false (uses cached workflows when a good match exists).' 'Returns a preview — call again with confirm_deploy=true to deploy it.'
},
deploy_id: {
type: 'string',
description: 'ID of a proposal to deploy. Get proposal IDs from a previous call ' +
'that returned status "proposals".'
},
confirm_deploy: {
type: 'boolean',
description: 'Set to true to deploy the workflow from the last generation preview.'
} }
}, },
required: ['description'], required: ['description'],

View File

@@ -3,11 +3,23 @@ import { InstanceContext } from './instance-context';
export interface GenerateWorkflowArgs { export interface GenerateWorkflowArgs {
description: string; description: string;
skip_cache?: boolean; skip_cache?: boolean;
deploy_id?: string;
confirm_deploy?: boolean;
}
export interface GenerateWorkflowProposal {
id: string;
name: string;
description: string;
flow_summary: string;
credentials_needed: string[];
} }
export interface GenerateWorkflowResult { export interface GenerateWorkflowResult {
success: boolean; success: boolean;
source?: 'cache' | 'generated'; source?: 'cache' | 'generated';
status?: 'proposals' | 'preview' | 'deployed' | 'error';
proposals?: GenerateWorkflowProposal[];
workflow_id?: string; workflow_id?: string;
workflow_name?: string; workflow_name?: string;
workflow_url?: string; workflow_url?: string;

View File

@@ -4,6 +4,7 @@ import type {
GenerateWorkflowHandler, GenerateWorkflowHandler,
GenerateWorkflowArgs, GenerateWorkflowArgs,
GenerateWorkflowResult, GenerateWorkflowResult,
GenerateWorkflowProposal,
GenerateWorkflowHelpers, GenerateWorkflowHelpers,
} from '@/types/generate-workflow'; } from '@/types/generate-workflow';
@@ -18,6 +19,8 @@ describe('n8n_generate_workflow', () => {
it('has correct input schema', () => { it('has correct input schema', () => {
expect(tool!.inputSchema.properties).toHaveProperty('description'); expect(tool!.inputSchema.properties).toHaveProperty('description');
expect(tool!.inputSchema.properties).toHaveProperty('skip_cache'); expect(tool!.inputSchema.properties).toHaveProperty('skip_cache');
expect(tool!.inputSchema.properties).toHaveProperty('deploy_id');
expect(tool!.inputSchema.properties).toHaveProperty('confirm_deploy');
expect(tool!.inputSchema.required).toEqual(['description']); expect(tool!.inputSchema.required).toEqual(['description']);
}); });
@@ -78,13 +81,69 @@ describe('n8n_generate_workflow', () => {
expect(failure.success).toBe(false); expect(failure.success).toBe(false);
}); });
it('GenerateWorkflowArgs has description and optional skip_cache', () => { it('GenerateWorkflowResult supports proposal status', () => {
const proposals: GenerateWorkflowResult = {
success: true,
status: 'proposals',
proposals: [
{
id: 'uuid-1',
name: 'Slack Reminder',
description: 'Send scheduled Slack messages',
flow_summary: 'Schedule Trigger → Set → Slack',
credentials_needed: ['slackApi'],
},
],
};
expect(proposals.status).toBe('proposals');
expect(proposals.proposals).toHaveLength(1);
expect(proposals.proposals![0].id).toBe('uuid-1');
});
it('GenerateWorkflowResult supports preview and deployed status', () => {
const preview: GenerateWorkflowResult = {
success: true,
status: 'preview',
node_summary: 'Webhook → HTTP Request → Slack',
};
expect(preview.status).toBe('preview');
const deployed: GenerateWorkflowResult = {
success: true,
status: 'deployed',
workflow_id: '123',
workflow_name: 'My Workflow',
};
expect(deployed.status).toBe('deployed');
});
it('GenerateWorkflowProposal has required fields', () => {
const proposal: GenerateWorkflowProposal = {
id: 'uuid-123',
name: 'Test Workflow',
description: 'A test workflow',
flow_summary: 'Trigger → Action',
credentials_needed: ['slackApi', 'gmailOAuth2'],
};
expect(proposal.id).toBe('uuid-123');
expect(proposal.credentials_needed).toHaveLength(2);
});
it('GenerateWorkflowArgs has description and optional fields', () => {
const minimal: GenerateWorkflowArgs = { description: 'test' }; const minimal: GenerateWorkflowArgs = { description: 'test' };
expect(minimal.description).toBe('test'); expect(minimal.description).toBe('test');
expect(minimal.skip_cache).toBeUndefined(); expect(minimal.skip_cache).toBeUndefined();
expect(minimal.deploy_id).toBeUndefined();
expect(minimal.confirm_deploy).toBeUndefined();
const withSkip: GenerateWorkflowArgs = { description: 'test', skip_cache: true }; const withSkip: GenerateWorkflowArgs = { description: 'test', skip_cache: true };
expect(withSkip.skip_cache).toBe(true); expect(withSkip.skip_cache).toBe(true);
const withDeploy: GenerateWorkflowArgs = { description: 'test', deploy_id: 'uuid-1' };
expect(withDeploy.deploy_id).toBe('uuid-1');
const withConfirm: GenerateWorkflowArgs = { description: 'test', confirm_deploy: true };
expect(withConfirm.confirm_deploy).toBe(true);
}); });
}); });
}); });