mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-04-02 23:53:07 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca20586eda | ||
|
|
8888c63e7a | ||
|
|
4b109b0870 | ||
|
|
b800ff0cd9 |
@@ -1,10 +1,9 @@
|
||||
---
|
||||
name: n8n-mcp-tester
|
||||
description: Use this agent when you need to test n8n-mcp functionality after implementing fixes or new features. This agent should be invoked proactively after code changes to validate that the MCP tools work correctly with real n8n workflows. The agent tests the actual MCP server tools, not just unit tests. Examples:\n\n<example>\nContext: Developer has just fixed a validation bug in the n8n-mcp server\nuser: "I've fixed the validation issue for HTTP Request nodes"\nassistant: "I've completed the fix. Now let me build the project and then test it."\n<builds project>\nassistant: "Project built successfully. Please reload the MCP server in Claude Desktop to apply the changes."\nuser: "Reloaded"\nassistant: "Great! Now let me invoke the n8n-mcp-tester agent to verify the fix works correctly."\n<commentary>\nSince a fix has been implemented and the MCP server reloaded, use the n8n-mcp-tester agent to validate the fix works in real-world usage.\n</commentary>\n</example>\n\n<example>\nContext: Developer has added a new MCP tool for workflow validation\nuser: "I've implemented the new workflow validation tool"\nassistant: "Implementation complete. Let me build and prepare for testing."\n<builds project>\nassistant: "Build successful. Please reload the MCP server to load the new tool."\nuser: "Done"\nassistant: "Perfect! I'll now use the n8n-mcp-tester agent to test the new workflow validation tool."\n<commentary>\nAfter implementing new MCP functionality and reloading the server, invoke n8n-mcp-tester to verify it works correctly.\n</commentary>\n</example>
|
||||
tools: Glob, Grep, Read, WebFetch, TodoWrite, WebSearch, mcp__supabase__create_branch, mcp__supabase__list_branches, mcp__supabase__delete_branch, mcp__supabase__merge_branch, mcp__supabase__reset_branch, mcp__supabase__rebase_branch, mcp__supabase__list_tables, mcp__supabase__list_extensions, mcp__supabase__list_migrations, mcp__supabase__apply_migration, mcp__supabase__execute_sql, mcp__supabase__get_logs, mcp__supabase__get_advisors, mcp__supabase__get_project_url, mcp__supabase__generate_typescript_types, mcp__supabase__search_docs, mcp__supabase__list_edge_functions, mcp__supabase__deploy_edge_function, mcp__n8n-mcp__tools_documentation, mcp__n8n-mcp__search_nodes, mcp__n8n-mcp__get_template, mcp__n8n-mcp__search_templates, mcp__n8n-mcp__validate_workflow, mcp__n8n-mcp__n8n_create_workflow, mcp__n8n-mcp__n8n_get_workflow, mcp__n8n-mcp__n8n_update_full_workflow, mcp__n8n-mcp__n8n_update_partial_workflow, mcp__n8n-mcp__n8n_delete_workflow, mcp__n8n-mcp__n8n_list_workflows, mcp__n8n-mcp__n8n_validate_workflow, mcp__n8n-mcp__n8n_trigger_webhook_workflow, mcp__n8n-mcp__n8n_health_check, mcp__brightdata-mcp__search_engine, mcp__brightdata-mcp__scrape_as_markdown, mcp__brightdata-mcp__search_engine_batch, mcp__brightdata-mcp__scrape_batch, mcp__supabase__get_publishable_keys, mcp__supabase__get_edge_function, mcp__n8n-mcp__get_node, mcp__n8n-mcp__validate_node, mcp__n8n-mcp__n8n_autofix_workflow, mcp__n8n-mcp__n8n_executions, mcp__n8n-mcp__n8n_workflow_versions, mcp__n8n-mcp__n8n_deploy_template, mcp__ide__getDiagnostics, mcp__ide__executeCode
|
||||
description: "Use this agent when you need to test n8n-mcp functionality after implementing fixes or new features. This agent should be invoked proactively after code changes to validate that the MCP tools work correctly with real n8n workflows. The agent tests the actual MCP server tools, not just unit tests. Examples:\\n\\n<example>\\nContext: Developer has just fixed a validation bug in the n8n-mcp server\\nuser: \"I've fixed the validation issue for HTTP Request nodes\"\\nassistant: \"I've completed the fix. Now let me build the project and then test it.\"\\n<builds project>\\nassistant: \"Project built successfully. Please reload the MCP server in Claude Desktop to apply the changes.\"\\nuser: \"Reloaded\"\\nassistant: \"Great! Now let me invoke the n8n-mcp-tester agent to verify the fix works correctly.\"\\n<commentary>\\nSince a fix has been implemented and the MCP server reloaded, use the n8n-mcp-tester agent to validate the fix works in real-world usage.\\n</commentary>\\n</example>\\n\\n<example>\\nContext: Developer has added a new MCP tool for workflow validation\\nuser: \"I've implemented the new workflow validation tool\"\\nassistant: \"Implementation complete. Let me build and prepare for testing.\"\\n<builds project>\\nassistant: \"Build successful. Please reload the MCP server to load the new tool.\"\\nuser: \"Done\"\\nassistant: \"Perfect! I'll now use the n8n-mcp-tester agent to test the new workflow validation tool.\"\\n<commentary>\\nAfter implementing new MCP functionality and reloading the server, invoke n8n-mcp-tester to verify it works correctly.\\n</commentary>\\n</example>"
|
||||
tools: "Glob, Grep, Read, WebFetch, WebSearch, ListMcpResourcesTool, ReadMcpResourceTool, Bash, mcp__context7__query-docs, mcp__context7__resolve-library-id, mcp__n8n-mcp-testing__get_node, mcp__n8n-mcp-testing__get_template, mcp__n8n-mcp-testing__n8n_autofix_workflow, mcp__n8n-mcp-testing__n8n_create_workflow, mcp__n8n-mcp-testing__n8n_delete_workflow, mcp__n8n-mcp-testing__n8n_deploy_template, mcp__n8n-mcp-testing__n8n_executions, mcp__n8n-mcp-testing__n8n_generate_workflow, mcp__n8n-mcp-testing__n8n_get_workflow, mcp__n8n-mcp-testing__n8n_health_check, mcp__n8n-mcp-testing__n8n_list_workflows, mcp__n8n-mcp-testing__n8n_manage_datatable, mcp__n8n-mcp-testing__n8n_test_workflow, mcp__n8n-mcp-testing__n8n_update_full_workflow, mcp__n8n-mcp-testing__n8n_update_partial_workflow, mcp__n8n-mcp-testing__n8n_validate_workflow, mcp__n8n-mcp-testing__n8n_workflow_versions, mcp__n8n-mcp-testing__search_nodes, mcp__n8n-mcp-testing__search_templates, mcp__n8n-mcp-testing__tools_documentation, mcp__n8n-mcp-testing__validate_node, mcp__n8n-mcp-testing__validate_workflow, mcp__plugin_postgres-best-practices_supabase__authenticate, mcp__supabase-telemetry__apply_migration, mcp__supabase-telemetry__create_branch, mcp__supabase-telemetry__delete_branch, mcp__supabase-telemetry__deploy_edge_function, mcp__supabase-telemetry__execute_sql, mcp__supabase-telemetry__generate_typescript_types, mcp__supabase-telemetry__get_advisors, mcp__supabase-telemetry__get_edge_function, mcp__supabase-telemetry__get_logs, mcp__supabase-telemetry__get_project_url, mcp__supabase-telemetry__get_publishable_keys, mcp__supabase-telemetry__list_branches, mcp__supabase-telemetry__list_edge_functions, mcp__supabase-telemetry__list_extensions, mcp__supabase-telemetry__list_migrations, mcp__supabase-telemetry__list_tables, mcp__supabase-telemetry__merge_branch, mcp__supabase-telemetry__rebase_branch, mcp__supabase-telemetry__reset_branch, mcp__supabase-telemetry__search_docs"
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
You are n8n-mcp-tester, a specialized testing agent for the n8n Model Context Protocol (MCP) server. You validate that MCP tools and functionality work correctly in real-world scenarios after fixes or new features are implemented.
|
||||
|
||||
## Your Core Responsibilities
|
||||
|
||||
8
.github/workflows/docker-build-fast.yml
vendored
8
.github/workflows/docker-build-fast.yml
vendored
@@ -36,11 +36,11 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
type=raw,value=test-amd64
|
||||
|
||||
- name: Build and push Docker image (AMD64 only)
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
14
.github/workflows/docker-build-n8n.yml
vendored
14
.github/workflows/docker-build-n8n.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
@@ -62,11 +62,11 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
generate_release_notes: true
|
||||
body: |
|
||||
|
||||
20
.github/workflows/docker-build.yml
vendored
20
.github/workflows/docker-build.yml
vendored
@@ -78,15 +78,15 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
no-cache: false
|
||||
@@ -186,15 +186,15 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Railway
|
||||
id: meta-railway
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
||||
tags: |
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Railway Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.railway
|
||||
|
||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -389,7 +389,7 @@ jobs:
|
||||
echo "Version: $(node -e "console.log(require('./package.json').version)")"
|
||||
|
||||
- name: Publish to NPM with retry
|
||||
uses: nick-invision/retry@v2
|
||||
uses: nick-invision/retry@v4
|
||||
with:
|
||||
timeout_minutes: 5
|
||||
max_attempts: 3
|
||||
@@ -448,13 +448,13 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -462,7 +462,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for standard image
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -472,7 +472,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push standard Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
@@ -553,7 +553,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Railway image
|
||||
id: meta-railway
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
||||
tags: |
|
||||
@@ -563,7 +563,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Railway Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.railway
|
||||
|
||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -116,7 +116,7 @@ jobs:
|
||||
# Upload coverage to Codecov
|
||||
- name: Upload coverage to Codecov
|
||||
if: always()
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: ./coverage/lcov.info
|
||||
@@ -250,7 +250,7 @@ jobs:
|
||||
path: artifacts
|
||||
|
||||
- name: Publish test results
|
||||
uses: dorny/test-reporter@v1
|
||||
uses: dorny/test-reporter@v3
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
|
||||
2
.github/workflows/update-n8n-deps.yml
vendored
2
.github/workflows/update-n8n-deps.yml
vendored
@@ -129,7 +129,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.branch.outputs.branch_name != ''
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ steps.branch.outputs.branch_name }}
|
||||
|
||||
57
CHANGELOG.md
57
CHANGELOG.md
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.45.1] - 2026-04-02
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Use stdio-wrapper.js as default bin entry point** — the previous entry point (`index.js`) wrote INFO-level logs to stdout, corrupting JSON-RPC MCP transport for stdio-mode users (Fixes #693, Related: #555, #628)
|
||||
- **Preserve node credentials during full workflow updates** — `n8n_update_full_workflow` now carries forward existing credential references from the server when user-provided nodes omit them, preventing "missing credentials" errors on PUT (Fixes #689)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Updated publish scripts** to use `stdio-wrapper.js` as the npm bin entry point, ensuring the fix persists across releases
|
||||
|
||||
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||
|
||||
## [2.45.0] - 2026-04-01
|
||||
|
||||
### Changed
|
||||
|
||||
- **Update n8n dependencies** to latest versions:
|
||||
- `n8n`: 2.13.3 → 2.14.2
|
||||
- `n8n-core`: 2.13.1 → 2.14.1
|
||||
- `n8n-workflow`: 2.13.1 → 2.14.1
|
||||
- `@n8n/n8n-nodes-langchain`: 2.13.1 → 2.14.1
|
||||
- **Rebuild FTS5 search index** with all 1396 nodes (812 base + 584 community)
|
||||
|
||||
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||
|
||||
## [2.44.1] - 2026-04-01
|
||||
|
||||
### Security
|
||||
|
||||
- **Bump axios** from `^1.11.0` to `^1.14.0` to patch known vulnerability
|
||||
- **Bump nodemon** from `^3.1.10` to `^3.1.14` to patch transitive dependency vulnerabilities
|
||||
|
||||
### Changed
|
||||
|
||||
- **Upgrade GitHub Actions** to latest versions across all CI/CD workflows (docker, release, test, update-n8n-deps) — contributed by @salmanmkc in #663
|
||||
|
||||
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||
|
||||
## [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
|
||||
|
||||
### Added
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[](https://www.npmjs.com/package/n8n-mcp)
|
||||
[](https://codecov.io/gh/czlonkowski/n8n-mcp)
|
||||
[](https://github.com/czlonkowski/n8n-mcp/actions)
|
||||
[](https://github.com/n8n-io/n8n)
|
||||
[](https://github.com/n8n-io/n8n)
|
||||
[](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
||||
[](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
|
||||
|
||||
|
||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
2
dist/index.d.ts
vendored
2
dist/index.d.ts
vendored
@@ -5,7 +5,7 @@ export { N8NDocumentationMCPServer } from './mcp/server';
|
||||
export type { InstanceContext } from './types/instance-context';
|
||||
export { validateInstanceContext, isInstanceContext } from './types/instance-context';
|
||||
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 { UI_APP_CONFIGS } from './mcp/ui/app-configs';
|
||||
export type { Tool, CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
2
dist/index.d.ts.map
vendored
2
dist/index.d.ts.map
vendored
@@ -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
2
dist/index.js.map
vendored
@@ -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"}
|
||||
2
dist/mcp/server.d.ts.map
vendored
2
dist/mcp/server.d.ts.map
vendored
@@ -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
2
dist/mcp/server.js
vendored
@@ -1156,7 +1156,7 @@ class N8NDocumentationMCPServer {
|
||||
getWorkflow: (id) => n8nHandlers.handleGetWorkflow({ id }, ctx),
|
||||
};
|
||||
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' };
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
2
dist/mcp/server.js.map
vendored
2
dist/mcp/server.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/mcp/tools-n8n-manager.d.ts.map
vendored
2
dist/mcp/tools-n8n-manager.d.ts.map
vendored
@@ -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"}
|
||||
20
dist/mcp/tools-n8n-manager.js
vendored
20
dist/mcp/tools-n8n-manager.js
vendored
@@ -638,9 +638,10 @@ exports.n8nManagementTools = [
|
||||
{
|
||||
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.',
|
||||
'Call with just a description to get workflow proposals. ' +
|
||||
'Then call again with deploy_id to deploy a chosen proposal, ' +
|
||||
'or set skip_cache=true to generate a fresh workflow. ' +
|
||||
'Use confirm_deploy=true to deploy a previously generated workflow.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -651,8 +652,17 @@ exports.n8nManagementTools = [
|
||||
},
|
||||
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).'
|
||||
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.'
|
||||
}
|
||||
},
|
||||
required: ['description'],
|
||||
|
||||
2
dist/mcp/tools-n8n-manager.js.map
vendored
2
dist/mcp/tools-n8n-manager.js.map
vendored
File diff suppressed because one or more lines are too long
2281
package-lock.json
generated
2281
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "n8n-mcp",
|
||||
"version": "2.43.0",
|
||||
"version": "2.45.1",
|
||||
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -12,7 +12,7 @@
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"n8n-mcp": "./dist/mcp/index.js"
|
||||
"n8n-mcp": "./dist/mcp/stdio-wrapper.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
@@ -140,27 +140,27 @@
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/runner": "^3.2.4",
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"axios": "^1.11.0",
|
||||
"axios": "^1.14.0",
|
||||
"axios-mock-adapter": "^2.1.0",
|
||||
"fishery": "^2.3.1",
|
||||
"msw": "^2.10.4",
|
||||
"nodemon": "^3.1.10",
|
||||
"nodemon": "^3.1.14",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "1.28.0",
|
||||
"@n8n/n8n-nodes-langchain": "^2.13.1",
|
||||
"@n8n/n8n-nodes-langchain": "^2.14.1",
|
||||
"@supabase/supabase-js": "^2.57.4",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"express-rate-limit": "^7.1.5",
|
||||
"form-data": "^4.0.5",
|
||||
"lru-cache": "^11.2.1",
|
||||
"n8n": "^2.13.3",
|
||||
"n8n-core": "^2.13.1",
|
||||
"n8n-workflow": "^2.13.1",
|
||||
"n8n": "^2.14.2",
|
||||
"n8n-core": "^2.14.1",
|
||||
"n8n-workflow": "^2.14.1",
|
||||
"openai": "^4.77.0",
|
||||
"sql.js": "^1.13.0",
|
||||
"tslib": "^2.6.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "n8n-mcp-runtime",
|
||||
"version": "2.33.2",
|
||||
"version": "2.45.1",
|
||||
"description": "n8n MCP Server Runtime Dependencies Only",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -35,7 +35,7 @@ node -e "
|
||||
const pkg = require('./package.json');
|
||||
pkg.name = 'n8n-mcp';
|
||||
pkg.description = 'Integration between n8n workflow automation and Model Context Protocol (MCP)';
|
||||
pkg.bin = { 'n8n-mcp': './dist/mcp/index.js' };
|
||||
pkg.bin = { 'n8n-mcp': './dist/mcp/stdio-wrapper.js' };
|
||||
pkg.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
|
||||
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
||||
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
||||
|
||||
@@ -68,7 +68,7 @@ pkg.exports = {
|
||||
import: './dist/index.js'
|
||||
}
|
||||
};
|
||||
pkg.bin = { 'n8n-mcp': './dist/mcp/index.js' };
|
||||
pkg.bin = { 'n8n-mcp': './dist/mcp/stdio-wrapper.js' };
|
||||
pkg.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
|
||||
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
||||
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
||||
|
||||
@@ -24,6 +24,7 @@ export type {
|
||||
export type {
|
||||
GenerateWorkflowArgs,
|
||||
GenerateWorkflowResult,
|
||||
GenerateWorkflowProposal,
|
||||
GenerateWorkflowHandler,
|
||||
GenerateWorkflowHelpers
|
||||
} from './types/generate-workflow';
|
||||
|
||||
@@ -776,6 +776,28 @@ export async function handleUpdateWorkflow(
|
||||
const current = await client.getWorkflow(id);
|
||||
workflowBefore = JSON.parse(JSON.stringify(current));
|
||||
|
||||
// Preserve credentials from current workflow for nodes that don't specify them.
|
||||
// AI-generated node updates typically omit credential references because they
|
||||
// aren't included in the context provided to the AI. Without this merge, the
|
||||
// n8n API rejects the PUT with missing credentials.
|
||||
if (updateData.nodes && current.nodes) {
|
||||
const currentById = new Map<string, any>();
|
||||
const currentByName = new Map<string, any>();
|
||||
for (const node of current.nodes) {
|
||||
if (node.id) currentById.set(node.id, node);
|
||||
currentByName.set(node.name, node);
|
||||
}
|
||||
for (const node of updateData.nodes as any[]) {
|
||||
const hasCredentials = node.credentials && typeof node.credentials === 'object' && Object.keys(node.credentials).length > 0;
|
||||
if (!hasCredentials) {
|
||||
const match = (node.id && currentById.get(node.id)) || currentByName.get(node.name);
|
||||
if (match?.credentials) {
|
||||
node.credentials = match.credentials;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create backup before modifying workflow (default: true)
|
||||
if (createBackup !== false) {
|
||||
try {
|
||||
|
||||
@@ -1561,11 +1561,7 @@ export class N8NDocumentationMCPServer {
|
||||
};
|
||||
|
||||
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' };
|
||||
} catch (err: any) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
|
||||
@@ -4,58 +4,84 @@ 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'],
|
||||
description: 'Generate workflows from natural language. Three-step flow:\n' +
|
||||
'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"})',
|
||||
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',
|
||||
'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'
|
||||
]
|
||||
},
|
||||
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: {
|
||||
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: [
|
||||
`// Generate a simple scheduled workflow
|
||||
`// Step 1: Get proposals
|
||||
n8n_generate_workflow({
|
||||
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({
|
||||
description: "When a new row is added to Google Sheets, create a task in Notion and notify via email"
|
||||
})`,
|
||||
`// Force fresh generation (skip cache)
|
||||
description: "Send a Slack message every morning at 9am",
|
||||
deploy_id: "uuid-1"
|
||||
})
|
||||
// Returns: { status: "deployed", workflow_id: "123", ... }`,
|
||||
`// Step 2b: Fresh generation (skip cache)
|
||||
n8n_generate_workflow({
|
||||
description: "Webhook that receives JSON data, transforms it, and posts to a REST API",
|
||||
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: [
|
||||
'Quickly create workflows from natural language descriptions',
|
||||
'Generate complex multi-service integrations',
|
||||
'Bootstrap automation projects with AI-generated workflows',
|
||||
'Review proposals before deploying to maintain quality',
|
||||
'Generate complex multi-service integrations with agent oversight',
|
||||
'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: [
|
||||
'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'
|
||||
'Review proposals before deploying — pick the best match with deploy_id',
|
||||
'Use skip_cache only when proposals do not match your needs',
|
||||
'After deployment, use n8n_validate_workflow to verify the result',
|
||||
'Configure credentials in n8n UI before activating'
|
||||
],
|
||||
pitfalls: [
|
||||
'**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',
|
||||
'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']
|
||||
}
|
||||
|
||||
@@ -657,9 +657,10 @@ export const n8nManagementTools: ToolDefinition[] = [
|
||||
{
|
||||
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.',
|
||||
'Call with just a description to get workflow proposals. ' +
|
||||
'Then call again with deploy_id to deploy a chosen proposal, ' +
|
||||
'or set skip_cache=true to generate a fresh workflow. ' +
|
||||
'Use confirm_deploy=true to deploy a previously generated workflow.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -670,8 +671,17 @@ export const n8nManagementTools: ToolDefinition[] = [
|
||||
},
|
||||
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).'
|
||||
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.'
|
||||
}
|
||||
},
|
||||
required: ['description'],
|
||||
|
||||
@@ -3,11 +3,23 @@ import { InstanceContext } from './instance-context';
|
||||
export interface GenerateWorkflowArgs {
|
||||
description: string;
|
||||
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 {
|
||||
success: boolean;
|
||||
source?: 'cache' | 'generated';
|
||||
status?: 'proposals' | 'preview' | 'deployed' | 'error';
|
||||
proposals?: GenerateWorkflowProposal[];
|
||||
workflow_id?: string;
|
||||
workflow_name?: string;
|
||||
workflow_url?: string;
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
GenerateWorkflowHandler,
|
||||
GenerateWorkflowArgs,
|
||||
GenerateWorkflowResult,
|
||||
GenerateWorkflowProposal,
|
||||
GenerateWorkflowHelpers,
|
||||
} from '@/types/generate-workflow';
|
||||
|
||||
@@ -18,6 +19,8 @@ describe('n8n_generate_workflow', () => {
|
||||
it('has correct input schema', () => {
|
||||
expect(tool!.inputSchema.properties).toHaveProperty('description');
|
||||
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']);
|
||||
});
|
||||
|
||||
@@ -78,13 +81,69 @@ describe('n8n_generate_workflow', () => {
|
||||
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' };
|
||||
expect(minimal.description).toBe('test');
|
||||
expect(minimal.skip_cache).toBeUndefined();
|
||||
expect(minimal.deploy_id).toBeUndefined();
|
||||
expect(minimal.confirm_deploy).toBeUndefined();
|
||||
|
||||
const withSkip: GenerateWorkflowArgs = { description: 'test', skip_cache: 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,12 @@ import { ExecutionStatus } from '@/types/n8n-api';
|
||||
vi.mock('@/services/n8n-api-client');
|
||||
vi.mock('@/services/workflow-validator');
|
||||
vi.mock('@/database/node-repository');
|
||||
vi.mock('@/services/workflow-versioning-service', () => ({
|
||||
WorkflowVersioningService: vi.fn().mockImplementation(() => ({
|
||||
createBackup: vi.fn().mockResolvedValue({ versionId: 'v1', versionNumber: 1, pruned: 0 }),
|
||||
getVersions: vi.fn().mockResolvedValue([]),
|
||||
})),
|
||||
}));
|
||||
vi.mock('@/config/n8n-api', () => ({
|
||||
getN8nApiConfig: vi.fn()
|
||||
}));
|
||||
@@ -1343,4 +1349,142 @@ describe('handlers-n8n-manager', () => {
|
||||
expect(result.error).toMatch(/mode:\s*'preview'/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleUpdateWorkflow - credential preservation', () => {
|
||||
function mockCurrentWorkflow(nodes: any[]): void {
|
||||
const workflow = createTestWorkflow({ id: 'wf-1', active: false, nodes });
|
||||
mockApiClient.getWorkflow.mockResolvedValue(workflow);
|
||||
mockApiClient.updateWorkflow.mockResolvedValue({ ...workflow, updatedAt: '2024-01-02' });
|
||||
}
|
||||
|
||||
function getSentNodes(): any[] {
|
||||
return mockApiClient.updateWorkflow.mock.calls[0][1].nodes;
|
||||
}
|
||||
|
||||
it('should preserve credentials from current workflow when update nodes omit them', async () => {
|
||||
mockCurrentWorkflow([
|
||||
{
|
||||
id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres',
|
||||
typeVersion: 2, position: [100, 100],
|
||||
parameters: { operation: 'executeQuery', query: 'SELECT 1' },
|
||||
credentials: { postgresApi: { id: 'cred-123', name: 'My Postgres' } },
|
||||
},
|
||||
{
|
||||
id: 'node-2', name: 'HTTP Request', type: 'n8n-nodes-base.httpRequest',
|
||||
typeVersion: 4, position: [300, 100],
|
||||
parameters: { url: 'https://example.com' },
|
||||
credentials: { httpBasicAuth: { id: 'cred-456', name: 'Basic Auth' } },
|
||||
},
|
||||
{
|
||||
id: 'node-3', name: 'Set', type: 'n8n-nodes-base.set',
|
||||
typeVersion: 3, position: [500, 100], parameters: {},
|
||||
},
|
||||
]);
|
||||
|
||||
await handlers.handleUpdateWorkflow(
|
||||
{
|
||||
id: 'wf-1',
|
||||
nodes: [
|
||||
{
|
||||
id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres',
|
||||
typeVersion: 2, position: [100, 100],
|
||||
parameters: { operation: 'executeQuery', query: 'SELECT * FROM users' },
|
||||
},
|
||||
{
|
||||
id: 'node-2', name: 'HTTP Request', type: 'n8n-nodes-base.httpRequest',
|
||||
typeVersion: 4, position: [300, 100],
|
||||
parameters: { url: 'https://example.com/v2' },
|
||||
},
|
||||
{
|
||||
id: 'node-3', name: 'Set', type: 'n8n-nodes-base.set',
|
||||
typeVersion: 3, position: [500, 100], parameters: { mode: 'manual' },
|
||||
},
|
||||
],
|
||||
connections: {},
|
||||
},
|
||||
mockRepository,
|
||||
);
|
||||
|
||||
const sentNodes = getSentNodes();
|
||||
expect(sentNodes[0].credentials).toEqual({ postgresApi: { id: 'cred-123', name: 'My Postgres' } });
|
||||
expect(sentNodes[1].credentials).toEqual({ httpBasicAuth: { id: 'cred-456', name: 'Basic Auth' } });
|
||||
expect(sentNodes[2].credentials).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not overwrite user-provided credentials', async () => {
|
||||
mockCurrentWorkflow([
|
||||
{
|
||||
id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres',
|
||||
typeVersion: 2, position: [100, 100], parameters: {},
|
||||
credentials: { postgresApi: { id: 'cred-old', name: 'Old Postgres' } },
|
||||
},
|
||||
]);
|
||||
|
||||
await handlers.handleUpdateWorkflow(
|
||||
{
|
||||
id: 'wf-1',
|
||||
nodes: [
|
||||
{
|
||||
id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres',
|
||||
typeVersion: 2, position: [100, 100], parameters: {},
|
||||
credentials: { postgresApi: { id: 'cred-new', name: 'New Postgres' } },
|
||||
},
|
||||
],
|
||||
connections: {},
|
||||
},
|
||||
mockRepository,
|
||||
);
|
||||
|
||||
const sentNodes = getSentNodes();
|
||||
expect(sentNodes[0].credentials).toEqual({ postgresApi: { id: 'cred-new', name: 'New Postgres' } });
|
||||
});
|
||||
|
||||
it('should match nodes by name when ids differ', async () => {
|
||||
mockCurrentWorkflow([
|
||||
{
|
||||
id: 'server-id-1', name: 'Gmail', type: 'n8n-nodes-base.gmail',
|
||||
typeVersion: 2, position: [100, 100], parameters: {},
|
||||
credentials: { gmailOAuth2: { id: 'cred-gmail', name: 'Gmail' } },
|
||||
},
|
||||
]);
|
||||
|
||||
await handlers.handleUpdateWorkflow(
|
||||
{
|
||||
id: 'wf-1',
|
||||
nodes: [
|
||||
{
|
||||
id: 'client-id-different', name: 'Gmail', type: 'n8n-nodes-base.gmail',
|
||||
typeVersion: 2, position: [100, 100],
|
||||
parameters: { resource: 'message' },
|
||||
},
|
||||
],
|
||||
connections: {},
|
||||
},
|
||||
mockRepository,
|
||||
);
|
||||
|
||||
const sentNodes = getSentNodes();
|
||||
expect(sentNodes[0].credentials).toEqual({ gmailOAuth2: { id: 'cred-gmail', name: 'Gmail' } });
|
||||
});
|
||||
|
||||
it('should treat empty credentials object as missing and carry forward', async () => {
|
||||
mockCurrentWorkflow([
|
||||
{ id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres', typeVersion: 2, position: [100, 100], parameters: {}, credentials: { postgresApi: { id: 'cred-123', name: 'My Postgres' } } },
|
||||
]);
|
||||
|
||||
await handlers.handleUpdateWorkflow(
|
||||
{
|
||||
id: 'wf-1',
|
||||
nodes: [
|
||||
{ id: 'node-1', name: 'Postgres', type: 'n8n-nodes-base.postgres', typeVersion: 2, position: [100, 100], parameters: {}, credentials: {} },
|
||||
],
|
||||
connections: {},
|
||||
},
|
||||
mockRepository,
|
||||
);
|
||||
|
||||
const sentNodes = getSentNodes();
|
||||
expect(sentNodes[0].credentials).toEqual({ postgresApi: { id: 'cred-123', name: 'My Postgres' } });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user