mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-04-03 16:13:08 +00:00
Compare commits
11 Commits
fix/includ
...
v2.46.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d7d5bdb6 | ||
|
|
2d4115530c | ||
|
|
ca20586eda | ||
|
|
8888c63e7a | ||
|
|
4b109b0870 | ||
|
|
b800ff0cd9 | ||
|
|
77c92716a3 | ||
|
|
198e773bb3 | ||
|
|
3417c6701c | ||
|
|
5b68d7fa53 | ||
|
|
54e445bc6a |
@@ -1,10 +1,9 @@
|
|||||||
---
|
---
|
||||||
name: n8n-mcp-tester
|
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>
|
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
|
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
|
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.
|
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
|
## 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 }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata
|
- name: Extract metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
type=raw,value=test-amd64
|
type=raw,value=test-amd64
|
||||||
|
|
||||||
- name: Build and push Docker image (AMD64 only)
|
- name: Build and push Docker image (AMD64 only)
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64
|
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
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
@@ -62,11 +62,11 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -74,7 +74,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata
|
- name: Extract metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
@@ -85,7 +85,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
@@ -109,7 +109,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -167,7 +167,7 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
body: |
|
body: |
|
||||||
|
|||||||
20
.github/workflows/docker-build.yml
vendored
20
.github/workflows/docker-build.yml
vendored
@@ -78,15 +78,15 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -94,7 +94,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata
|
- name: Extract metadata
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
@@ -107,7 +107,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build and push Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
no-cache: false
|
no-cache: false
|
||||||
@@ -186,15 +186,15 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -202,7 +202,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata for Railway
|
- name: Extract metadata for Railway
|
||||||
id: meta-railway
|
id: meta-railway
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
||||||
tags: |
|
tags: |
|
||||||
@@ -215,7 +215,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push Railway Docker image
|
- name: Build and push Railway Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile.railway
|
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)")"
|
echo "Version: $(node -e "console.log(require('./package.json').version)")"
|
||||||
|
|
||||||
- name: Publish to NPM with retry
|
- name: Publish to NPM with retry
|
||||||
uses: nick-invision/retry@v2
|
uses: nick-invision/retry@v4
|
||||||
with:
|
with:
|
||||||
timeout_minutes: 5
|
timeout_minutes: 5
|
||||||
max_attempts: 3
|
max_attempts: 3
|
||||||
@@ -448,13 +448,13 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v4
|
||||||
|
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -462,7 +462,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata for standard image
|
- name: Extract metadata for standard image
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
@@ -472,7 +472,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push standard Docker image
|
- name: Build and push standard Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
@@ -553,7 +553,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Extract metadata for Railway image
|
- name: Extract metadata for Railway image
|
||||||
id: meta-railway
|
id: meta-railway
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v6
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
|
||||||
tags: |
|
tags: |
|
||||||
@@ -563,7 +563,7 @@ jobs:
|
|||||||
type=raw,value=latest,enable={{is_default_branch}}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
|
||||||
- name: Build and push Railway Docker image
|
- name: Build and push Railway Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile.railway
|
file: ./Dockerfile.railway
|
||||||
|
|||||||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -116,7 +116,7 @@ jobs:
|
|||||||
# Upload coverage to Codecov
|
# Upload coverage to Codecov
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
if: always()
|
if: always()
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./coverage/lcov.info
|
files: ./coverage/lcov.info
|
||||||
@@ -250,7 +250,7 @@ jobs:
|
|||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Publish test results
|
- name: Publish test results
|
||||||
uses: dorny/test-reporter@v1
|
uses: dorny/test-reporter@v3
|
||||||
if: always()
|
if: always()
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
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
|
- name: Create Pull Request
|
||||||
if: steps.branch.outputs.branch_name != ''
|
if: steps.branch.outputs.branch_name != ''
|
||||||
uses: peter-evans/create-pull-request@v5
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
branch: ${{ steps.branch.outputs.branch_name }}
|
branch: ${{ steps.branch.outputs.branch_name }}
|
||||||
|
|||||||
131
CHANGELOG.md
131
CHANGELOG.md
@@ -7,6 +7,137 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.46.1] - 2026-04-03
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Fix SSE reconnection loop** — SSE clients entering rapid reconnection loops because `POST /mcp` never routed messages to `SSEServerTransport.handlePostMessage()` (Fixes #617). Root cause: SSE sessions were stored in a separate `this.session` property invisible to the StreamableHTTP POST handler
|
||||||
|
- **Add authentication to SSE endpoints** — `GET /sse` and `POST /messages` now require Bearer token authentication, closing an auth gap where SSE connections were unauthenticated
|
||||||
|
- **Fix rate limiter exhaustion during reconnection** — added `skipSuccessfulRequests: true` to `authLimiter` so legitimate requests don't count toward the rate limit, preventing 429 storms during SSE reconnection loops
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Separate SSE endpoints (SDK pattern)** — SSE transport now uses dedicated `GET /sse` + `POST /messages` endpoints instead of sharing `/mcp` with StreamableHTTP, following the official MCP SDK backward-compatible server pattern
|
||||||
|
- **Unified auth into `authenticateRequest()` method** — consolidated duplicated Bearer token validation logic from three endpoints into a single method with consistent JSON-RPC error responses
|
||||||
|
- **SSE sessions use shared transports map** — removed the legacy `this.session` singleton; SSE sessions are now stored in the same `this.transports` map as StreamableHTTP sessions with `instanceof` guards for type discrimination
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- **SSE transport (`GET /sse`, `POST /messages`)** — SSE is deprecated in MCP SDK v1.x and removed in v2.x. Clients should migrate to StreamableHTTP (`POST /mcp`). These endpoints will be removed in a future major release
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- **Rate limiting on all authenticated endpoints** — `authLimiter` now applied to `GET /sse` and `POST /messages` in addition to `POST /mcp`
|
||||||
|
- **Transport type guards** — `instanceof` checks prevent cross-protocol access (SSE session IDs rejected on StreamableHTTP endpoint and vice versa)
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
|
## [2.46.0] - 2026-04-03
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **`patchNodeField` operation for `n8n_update_partial_workflow`** — a dedicated, strict find/replace operation for surgical string edits in node fields (Fixes #696). Key features:
|
||||||
|
- **Strict error handling**: errors if find string not found (unlike `__patch_find_replace` which only warns)
|
||||||
|
- **Ambiguity detection**: errors if find matches multiple times unless `replaceAll: true` is set
|
||||||
|
- **`replaceAll` flag**: replace all occurrences of a string in a single patch
|
||||||
|
- **`regex` flag**: use regex patterns for advanced find/replace
|
||||||
|
- Top-level operation type for better discoverability
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- **Prototype pollution protection** — `setNestedProperty` and `getNestedProperty` now reject paths containing `__proto__`, `constructor`, or `prototype`. Protects both `patchNodeField` and `updateNode` operations
|
||||||
|
- **ReDoS protection** — regex patterns with nested quantifiers or overlapping alternations are rejected to prevent catastrophic backtracking
|
||||||
|
- **Resource limits** — max 50 patches per operation, max 500-char regex patterns, max 512KB field size for regex operations
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
- **`n8n_generate_workflow` tool**: New MCP tool that enables AI-powered workflow generation from natural language descriptions. Available on the hosted service with handler delegation pattern for extensibility.
|
||||||
|
|
||||||
|
- **Handler injection API**: `EngineOptions.generateWorkflowHandler` allows hosting environments to provide custom workflow generation backends. Handler receives helpers for `createWorkflow`, `validateWorkflow`, `autofixWorkflow`, and `getWorkflow`.
|
||||||
|
|
||||||
|
- **Tool documentation**: Full essentials and deep documentation for `n8n_generate_workflow` via `tools_documentation`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Tools documentation count**: Corrected n8n API tools count and added missing `n8n_manage_datatable` entry to tools overview.
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
|
## [2.42.3] - 2026-03-30
|
||||||
|
|
||||||
|
### Improved
|
||||||
|
|
||||||
|
- **Patterns response trimmed for token efficiency** (Issue #683): Task-specific patterns response reduced ~64% — dropped redundant `displayName`, shortened field names (`frequency` → `freq`), capped chains at 5, and shortened chain node types to last segment.
|
||||||
|
|
||||||
|
- **`patterns` mode added to `tools_documentation`**: Was missing from both essentials and full docs. AI agents can now discover patterns mode through the standard documentation flow.
|
||||||
|
|
||||||
|
- **`includeOperations` omission behavior documented**: Added note that trigger nodes and freeform nodes (Code, HTTP Request) omit the `operationsTree` field.
|
||||||
|
|
||||||
|
- **`search_nodes` examples trimmed**: Reduced from 11 to 6 examples in full docs, removing near-duplicates.
|
||||||
|
|
||||||
|
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
## [2.42.2] - 2026-03-30
|
## [2.42.2] - 2026-03-30
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
[](https://www.npmjs.com/package/n8n-mcp)
|
[](https://www.npmjs.com/package/n8n-mcp)
|
||||||
[](https://codecov.io/gh/czlonkowski/n8n-mcp)
|
[](https://codecov.io/gh/czlonkowski/n8n-mcp)
|
||||||
[](https://github.com/czlonkowski/n8n-mcp/actions)
|
[](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://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
||||||
[](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
|
[](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
|
||||||
|
|
||||||
|
|||||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
12
dist/http-server-single-session.d.ts
vendored
12
dist/http-server-single-session.d.ts
vendored
@@ -2,19 +2,23 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { InstanceContext } from './types/instance-context';
|
import { InstanceContext } from './types/instance-context';
|
||||||
import { SessionState } from './types/session-state';
|
import { SessionState } from './types/session-state';
|
||||||
|
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||||
|
export interface SingleSessionHTTPServerOptions {
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
|
}
|
||||||
export declare class SingleSessionHTTPServer {
|
export declare class SingleSessionHTTPServer {
|
||||||
private transports;
|
private transports;
|
||||||
private servers;
|
private servers;
|
||||||
private sessionMetadata;
|
private sessionMetadata;
|
||||||
private sessionContexts;
|
private sessionContexts;
|
||||||
private contextSwitchLocks;
|
private contextSwitchLocks;
|
||||||
private session;
|
|
||||||
private consoleManager;
|
private consoleManager;
|
||||||
private expressServer;
|
private expressServer;
|
||||||
private sessionTimeout;
|
private sessionTimeout;
|
||||||
private authToken;
|
private authToken;
|
||||||
private cleanupTimer;
|
private cleanupTimer;
|
||||||
constructor();
|
private generateWorkflowHandler?;
|
||||||
|
constructor(options?: SingleSessionHTTPServerOptions);
|
||||||
private startSessionCleanup;
|
private startSessionCleanup;
|
||||||
private cleanupExpiredSessions;
|
private cleanupExpiredSessions;
|
||||||
private removeSession;
|
private removeSession;
|
||||||
@@ -24,14 +28,14 @@ export declare class SingleSessionHTTPServer {
|
|||||||
private isJsonRpcNotification;
|
private isJsonRpcNotification;
|
||||||
private sanitizeErrorForClient;
|
private sanitizeErrorForClient;
|
||||||
private updateSessionAccess;
|
private updateSessionAccess;
|
||||||
|
private authenticateRequest;
|
||||||
private switchSessionContext;
|
private switchSessionContext;
|
||||||
private performContextSwitch;
|
private performContextSwitch;
|
||||||
private getSessionMetrics;
|
private getSessionMetrics;
|
||||||
private loadAuthToken;
|
private loadAuthToken;
|
||||||
private validateEnvironment;
|
private validateEnvironment;
|
||||||
handleRequest(req: express.Request, res: express.Response, instanceContext?: InstanceContext): Promise<void>;
|
handleRequest(req: express.Request, res: express.Response, instanceContext?: InstanceContext): Promise<void>;
|
||||||
private resetSessionSSE;
|
private createSSESession;
|
||||||
private isExpired;
|
|
||||||
private isSessionExpired;
|
private isSessionExpired;
|
||||||
start(): Promise<void>;
|
start(): Promise<void>;
|
||||||
shutdown(): Promise<void>;
|
shutdown(): Promise<void>;
|
||||||
|
|||||||
2
dist/http-server-single-session.d.ts.map
vendored
2
dist/http-server-single-session.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"http-server-single-session.d.ts","sourceRoot":"","sources":["../src/http-server-single-session.ts"],"names":[],"mappings":";AAMA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAwErD,qBAAa,uBAAuB;IAElC,OAAO,CAAC,UAAU,CAA8D;IAChF,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,eAAe,CAAsE;IAC7F,OAAO,CAAC,eAAe,CAA4D;IACnF,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,aAAa,CAAM;IAI3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAA+B;;IAcnD,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,sBAAsB;YAqChB,aAAa;IAuC3B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,CAAC,mBAAmB;YASb,oBAAoB;YAwBpB,oBAAoB;IAwBlC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,mBAAmB;IAoDrB,aAAa,CACjB,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,EACrB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;YAoRF,eAAe;IA4D7B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,gBAAgB;IASlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgnBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B,cAAc,IAAI;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE;YACT,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,UAAU,EAAE,MAAM,EAAE,CAAC;SACtB,CAAC;KACH;IAmDM,kBAAkB,IAAI,YAAY,EAAE;IAoEpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;CAsG7D"}
|
{"version":3,"file":"http-server-single-session.d.ts","sourceRoot":"","sources":["../src/http-server-single-session.ts"],"names":[],"mappings":";AAMA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AA+DpE,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAED,qBAAa,uBAAuB;IAGlC,OAAO,CAAC,UAAU,CAAmF;IACrG,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,eAAe,CAAsE;IAC7F,OAAO,CAAC,eAAe,CAA4D;IACnF,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,aAAa,CAAM;IAG3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,uBAAuB,CAAC,CAA0B;gBAE9C,OAAO,CAAC,EAAE,8BAA8B;IAapD,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,sBAAsB;YAqChB,aAAa;IAuC3B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,mBAAmB;YAyCb,oBAAoB;YAwBpB,oBAAoB;IAwBlC,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,mBAAmB;IAoDrB,aAAa,CACjB,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,OAAO,CAAC,QAAQ,EACrB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;YAsSF,gBAAgB;IA+C9B,OAAO,CAAC,gBAAgB;IASlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAynBtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAgD/B,cAAc,IAAI;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE;YACT,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,OAAO,EAAE,MAAM,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC;YACZ,UAAU,EAAE,MAAM,EAAE,CAAC;SACtB,CAAC;KACH;IAmCM,kBAAkB,IAAI,YAAY,EAAE;IAoEpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;CAsG7D"}
|
||||||
372
dist/http-server-single-session.js
vendored
372
dist/http-server-single-session.js
vendored
@@ -45,17 +45,17 @@ function logSecurityEvent(event, details) {
|
|||||||
logger_1.logger.info(`[SECURITY] ${event}`, logEntry);
|
logger_1.logger.info(`[SECURITY] ${event}`, logEntry);
|
||||||
}
|
}
|
||||||
class SingleSessionHTTPServer {
|
class SingleSessionHTTPServer {
|
||||||
constructor() {
|
constructor(options) {
|
||||||
this.transports = {};
|
this.transports = {};
|
||||||
this.servers = {};
|
this.servers = {};
|
||||||
this.sessionMetadata = {};
|
this.sessionMetadata = {};
|
||||||
this.sessionContexts = {};
|
this.sessionContexts = {};
|
||||||
this.contextSwitchLocks = new Map();
|
this.contextSwitchLocks = new Map();
|
||||||
this.session = null;
|
|
||||||
this.consoleManager = new console_manager_1.ConsoleManager();
|
this.consoleManager = new console_manager_1.ConsoleManager();
|
||||||
this.sessionTimeout = parseInt(process.env.SESSION_TIMEOUT_MINUTES || '5', 10) * 60 * 1000;
|
this.sessionTimeout = parseInt(process.env.SESSION_TIMEOUT_MINUTES || '30', 10) * 60 * 1000;
|
||||||
this.authToken = null;
|
this.authToken = null;
|
||||||
this.cleanupTimer = null;
|
this.cleanupTimer = null;
|
||||||
|
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||||
this.validateEnvironment();
|
this.validateEnvironment();
|
||||||
this.startSessionCleanup();
|
this.startSessionCleanup();
|
||||||
}
|
}
|
||||||
@@ -169,6 +169,39 @@ class SingleSessionHTTPServer {
|
|||||||
this.sessionMetadata[sessionId].lastAccess = new Date();
|
this.sessionMetadata[sessionId].lastAccess = new Date();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
authenticateRequest(req, res) {
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
|
const reason = !authHeader ? 'no_auth_header' : 'invalid_auth_format';
|
||||||
|
logger_1.logger.warn('Authentication failed', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
reason
|
||||||
|
});
|
||||||
|
res.status(401).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32001, message: 'Unauthorized' },
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const token = authHeader.slice(7).trim();
|
||||||
|
const isValid = this.authToken && auth_1.AuthManager.timingSafeCompare(token, this.authToken);
|
||||||
|
if (!isValid) {
|
||||||
|
logger_1.logger.warn('Authentication failed: Invalid token', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
reason: 'invalid_token'
|
||||||
|
});
|
||||||
|
res.status(401).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32001, message: 'Unauthorized' },
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
async switchSessionContext(sessionId, newContext) {
|
async switchSessionContext(sessionId, newContext) {
|
||||||
const existingLock = this.contextSwitchLocks.get(sessionId);
|
const existingLock = this.contextSwitchLocks.get(sessionId);
|
||||||
if (existingLock) {
|
if (existingLock) {
|
||||||
@@ -340,7 +373,9 @@ class SingleSessionHTTPServer {
|
|||||||
else {
|
else {
|
||||||
sessionIdToUse = sessionId || (0, uuid_1.v4)();
|
sessionIdToUse = sessionId || (0, uuid_1.v4)();
|
||||||
}
|
}
|
||||||
const server = new server_1.N8NDocumentationMCPServer(instanceContext);
|
const server = new server_1.N8NDocumentationMCPServer(instanceContext, undefined, {
|
||||||
|
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||||
|
});
|
||||||
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
|
||||||
sessionIdGenerator: () => sessionIdToUse,
|
sessionIdGenerator: () => sessionIdToUse,
|
||||||
onsessioninitialized: (initializedSessionId) => {
|
onsessioninitialized: (initializedSessionId) => {
|
||||||
@@ -389,6 +424,18 @@ class SingleSessionHTTPServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger_1.logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
logger_1.logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
||||||
|
if (this.transports[sessionId] instanceof sse_js_1.SSEServerTransport) {
|
||||||
|
logger_1.logger.warn('handleRequest: SSE session used on StreamableHTTP endpoint', { sessionId });
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Session uses SSE transport. Send messages to POST /messages?sessionId=<id> instead.'
|
||||||
|
},
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
transport = this.transports[sessionId];
|
transport = this.transports[sessionId];
|
||||||
if (!transport) {
|
if (!transport) {
|
||||||
if (this.isJsonRpcNotification(req.body)) {
|
if (this.isJsonRpcNotification(req.body)) {
|
||||||
@@ -483,52 +530,33 @@ class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async resetSessionSSE(res) {
|
async createSSESession(res) {
|
||||||
if (this.session) {
|
if (!this.canCreateSession()) {
|
||||||
const sessionId = this.session.sessionId;
|
logger_1.logger.warn('SSE session creation rejected: session limit reached', {
|
||||||
logger_1.logger.info('Closing previous session for SSE', { sessionId });
|
currentSessions: this.getActiveSessionCount(),
|
||||||
if (this.session.server && typeof this.session.server.close === 'function') {
|
maxSessions: MAX_SESSIONS
|
||||||
try {
|
});
|
||||||
await this.session.server.close();
|
throw new Error(`Session limit reached (${MAX_SESSIONS})`);
|
||||||
}
|
|
||||||
catch (serverError) {
|
|
||||||
logger_1.logger.warn('Error closing server for SSE session', { sessionId, error: serverError });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await this.session.transport.close();
|
|
||||||
}
|
|
||||||
catch (transportError) {
|
|
||||||
logger_1.logger.warn('Error closing transport for SSE session', { sessionId, error: transportError });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try {
|
const server = new server_1.N8NDocumentationMCPServer(undefined, undefined, {
|
||||||
logger_1.logger.info('Creating new N8NDocumentationMCPServer for SSE...');
|
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||||
const server = new server_1.N8NDocumentationMCPServer();
|
});
|
||||||
const sessionId = (0, uuid_1.v4)();
|
const transport = new sse_js_1.SSEServerTransport('/messages', res);
|
||||||
logger_1.logger.info('Creating SSEServerTransport...');
|
const sessionId = transport.sessionId;
|
||||||
const transport = new sse_js_1.SSEServerTransport('/mcp', res);
|
this.transports[sessionId] = transport;
|
||||||
logger_1.logger.info('Connecting server to SSE transport...');
|
this.servers[sessionId] = server;
|
||||||
await server.connect(transport);
|
this.sessionMetadata[sessionId] = {
|
||||||
this.session = {
|
lastAccess: new Date(),
|
||||||
server,
|
createdAt: new Date()
|
||||||
transport,
|
};
|
||||||
lastAccess: new Date(),
|
res.on('close', () => {
|
||||||
sessionId,
|
logger_1.logger.info('SSE connection closed by client', { sessionId });
|
||||||
initialized: false,
|
this.removeSession(sessionId, 'sse_disconnect').catch(err => {
|
||||||
isSSE: true
|
logger_1.logger.warn('Error cleaning up SSE session on disconnect', { sessionId, error: err });
|
||||||
};
|
});
|
||||||
logger_1.logger.info('Created new SSE session successfully', { sessionId: this.session.sessionId });
|
});
|
||||||
}
|
await server.connect(transport);
|
||||||
catch (error) {
|
logger_1.logger.info('SSE session created', { sessionId, transport: 'SSEServerTransport' });
|
||||||
logger_1.logger.error('Failed to create SSE session:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isExpired() {
|
|
||||||
if (!this.session)
|
|
||||||
return true;
|
|
||||||
return Date.now() - this.session.lastAccess.getTime() > this.sessionTimeout;
|
|
||||||
}
|
}
|
||||||
isSessionExpired(sessionId) {
|
isSessionExpired(sessionId) {
|
||||||
const metadata = this.sessionMetadata[sessionId];
|
const metadata = this.sessionMetadata[sessionId];
|
||||||
@@ -596,7 +624,7 @@ class SingleSessionHTTPServer {
|
|||||||
authentication: {
|
authentication: {
|
||||||
type: 'Bearer Token',
|
type: 'Bearer Token',
|
||||||
header: 'Authorization: Bearer <token>',
|
header: 'Authorization: Bearer <token>',
|
||||||
required_for: ['POST /mcp']
|
required_for: ['POST /mcp', 'GET /sse', 'POST /messages']
|
||||||
},
|
},
|
||||||
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
||||||
});
|
});
|
||||||
@@ -628,7 +656,7 @@ class SingleSessionHTTPServer {
|
|||||||
},
|
},
|
||||||
activeTransports: activeTransports.length,
|
activeTransports: activeTransports.length,
|
||||||
activeServers: activeServers.length,
|
activeServers: activeServers.length,
|
||||||
legacySessionActive: !!this.session,
|
legacySessionActive: false,
|
||||||
memory: {
|
memory: {
|
||||||
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
||||||
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
|
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
|
||||||
@@ -668,9 +696,10 @@ class SingleSessionHTTPServer {
|
|||||||
});
|
});
|
||||||
app.get('/mcp', async (req, res) => {
|
app.get('/mcp', async (req, res) => {
|
||||||
const sessionId = req.headers['mcp-session-id'];
|
const sessionId = req.headers['mcp-session-id'];
|
||||||
if (sessionId && this.transports[sessionId]) {
|
const existingTransport = sessionId ? this.transports[sessionId] : undefined;
|
||||||
|
if (existingTransport && existingTransport instanceof streamableHttp_js_1.StreamableHTTPServerTransport) {
|
||||||
try {
|
try {
|
||||||
await this.transports[sessionId].handleRequest(req, res, undefined);
|
await existingTransport.handleRequest(req, res, undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@@ -679,22 +708,12 @@ class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
const accept = req.headers.accept;
|
const accept = req.headers.accept;
|
||||||
if (accept && accept.includes('text/event-stream')) {
|
if (accept && accept.includes('text/event-stream')) {
|
||||||
logger_1.logger.info('SSE stream request received - establishing SSE connection');
|
logger_1.logger.info('SSE request on /mcp redirected to /sse', { ip: req.ip });
|
||||||
try {
|
res.status(400).json({
|
||||||
await this.resetSessionSSE(res);
|
error: 'SSE transport uses /sse endpoint',
|
||||||
logger_1.logger.info('SSE connection established successfully');
|
message: 'Connect via GET /sse for SSE streaming. POST messages to /messages?sessionId=<id>.',
|
||||||
}
|
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
||||||
catch (error) {
|
});
|
||||||
logger_1.logger.error('Failed to establish SSE connection:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32603,
|
|
||||||
message: 'Failed to establish SSE connection'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (process.env.N8N_MODE === 'true') {
|
if (process.env.N8N_MODE === 'true') {
|
||||||
@@ -719,9 +738,23 @@ class SingleSessionHTTPServer {
|
|||||||
mcp: {
|
mcp: {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: '/mcp',
|
path: '/mcp',
|
||||||
description: 'Main MCP JSON-RPC endpoint',
|
description: 'Main MCP JSON-RPC endpoint (StreamableHTTP)',
|
||||||
authentication: 'Bearer token required'
|
authentication: 'Bearer token required'
|
||||||
},
|
},
|
||||||
|
sse: {
|
||||||
|
method: 'GET',
|
||||||
|
path: '/sse',
|
||||||
|
description: 'DEPRECATED: SSE stream for legacy clients. Migrate to StreamableHTTP (POST /mcp).',
|
||||||
|
authentication: 'Bearer token required',
|
||||||
|
deprecated: true
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
method: 'POST',
|
||||||
|
path: '/messages',
|
||||||
|
description: 'DEPRECATED: Message delivery for SSE sessions. Migrate to StreamableHTTP (POST /mcp).',
|
||||||
|
authentication: 'Bearer token required',
|
||||||
|
deprecated: true
|
||||||
|
},
|
||||||
health: {
|
health: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/health',
|
path: '/health',
|
||||||
@@ -738,6 +771,92 @@ class SingleSessionHTTPServer {
|
|||||||
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const authLimiter = (0, express_rate_limit_1.default)({
|
||||||
|
windowMs: parseInt(process.env.AUTH_RATE_LIMIT_WINDOW || '900000'),
|
||||||
|
max: parseInt(process.env.AUTH_RATE_LIMIT_MAX || '20'),
|
||||||
|
message: {
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Too many authentication attempts. Please try again later.'
|
||||||
|
},
|
||||||
|
id: null
|
||||||
|
},
|
||||||
|
standardHeaders: true,
|
||||||
|
legacyHeaders: false,
|
||||||
|
skipSuccessfulRequests: true,
|
||||||
|
handler: (req, res) => {
|
||||||
|
logger_1.logger.warn('Rate limit exceeded', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
event: 'rate_limit'
|
||||||
|
});
|
||||||
|
res.status(429).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Too many authentication attempts'
|
||||||
|
},
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.get('/sse', authLimiter, async (req, res) => {
|
||||||
|
if (!this.authenticateRequest(req, res))
|
||||||
|
return;
|
||||||
|
logger_1.logger.warn('SSE transport is deprecated and will be removed in a future release. Migrate to StreamableHTTP (POST /mcp).', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent')
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await this.createSSESession(res);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
logger_1.logger.error('Failed to create SSE session:', error);
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(error instanceof Error && error.message.includes('Session limit')
|
||||||
|
? 429 : 500).json({
|
||||||
|
error: error instanceof Error ? error.message : 'Failed to establish SSE connection'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.post('/messages', authLimiter, jsonParser, async (req, res) => {
|
||||||
|
if (!this.authenticateRequest(req, res))
|
||||||
|
return;
|
||||||
|
const sessionId = req.query.sessionId;
|
||||||
|
if (!sessionId) {
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32602, message: 'Missing sessionId query parameter' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const transport = this.transports[sessionId];
|
||||||
|
if (!transport || !(transport instanceof sse_js_1.SSEServerTransport)) {
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32000, message: 'SSE session not found or expired' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.updateSessionAccess(sessionId);
|
||||||
|
try {
|
||||||
|
await transport.handlePostMessage(req, res, req.body);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
logger_1.logger.error('SSE message handling error', { sessionId, error });
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(500).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32603, message: 'Internal error processing SSE message' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
app.delete('/mcp', async (req, res) => {
|
app.delete('/mcp', async (req, res) => {
|
||||||
const mcpSessionId = req.headers['mcp-session-id'];
|
const mcpSessionId = req.headers['mcp-session-id'];
|
||||||
if (!mcpSessionId) {
|
if (!mcpSessionId) {
|
||||||
@@ -791,35 +910,6 @@ class SingleSessionHTTPServer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const authLimiter = (0, express_rate_limit_1.default)({
|
|
||||||
windowMs: parseInt(process.env.AUTH_RATE_LIMIT_WINDOW || '900000'),
|
|
||||||
max: parseInt(process.env.AUTH_RATE_LIMIT_MAX || '20'),
|
|
||||||
message: {
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32000,
|
|
||||||
message: 'Too many authentication attempts. Please try again later.'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
},
|
|
||||||
standardHeaders: true,
|
|
||||||
legacyHeaders: false,
|
|
||||||
handler: (req, res) => {
|
|
||||||
logger_1.logger.warn('Rate limit exceeded', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
event: 'rate_limit'
|
|
||||||
});
|
|
||||||
res.status(429).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32000,
|
|
||||||
message: 'Too many authentication attempts'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.post('/mcp', authLimiter, jsonParser, async (req, res) => {
|
app.post('/mcp', authLimiter, jsonParser, async (req, res) => {
|
||||||
logger_1.logger.info('POST /mcp request received - DETAILED DEBUG', {
|
logger_1.logger.info('POST /mcp request received - DETAILED DEBUG', {
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
@@ -859,63 +949,10 @@ class SingleSessionHTTPServer {
|
|||||||
req.removeListener('close', closeHandler);
|
req.removeListener('close', closeHandler);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const authHeader = req.headers.authorization;
|
if (!this.authenticateRequest(req, res))
|
||||||
if (!authHeader) {
|
|
||||||
logger_1.logger.warn('Authentication failed: Missing Authorization header', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'no_auth_header'
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (!authHeader.startsWith('Bearer ')) {
|
|
||||||
logger_1.logger.warn('Authentication failed: Invalid Authorization header format (expected Bearer token)', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'invalid_auth_format',
|
|
||||||
headerPrefix: authHeader.substring(0, Math.min(authHeader.length, 10)) + '...'
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const token = authHeader.slice(7).trim();
|
|
||||||
const isValidToken = this.authToken &&
|
|
||||||
auth_1.AuthManager.timingSafeCompare(token, this.authToken);
|
|
||||||
if (!isValidToken) {
|
|
||||||
logger_1.logger.warn('Authentication failed: Invalid token', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'invalid_token'
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger_1.logger.info('Authentication successful - proceeding to handleRequest', {
|
logger_1.logger.info('Authentication successful - proceeding to handleRequest', {
|
||||||
hasSession: !!this.session,
|
activeSessions: this.getActiveSessionCount()
|
||||||
sessionType: this.session?.isSSE ? 'SSE' : 'StreamableHTTP',
|
|
||||||
sessionInitialized: this.session?.initialized
|
|
||||||
});
|
});
|
||||||
const instanceContext = (() => {
|
const instanceContext = (() => {
|
||||||
const headers = extractMultiTenantHeaders(req);
|
const headers = extractMultiTenantHeaders(req);
|
||||||
@@ -1003,6 +1040,7 @@ class SingleSessionHTTPServer {
|
|||||||
console.log(`Session Limits: ${MAX_SESSIONS} max sessions, ${this.sessionTimeout / 1000 / 60}min timeout`);
|
console.log(`Session Limits: ${MAX_SESSIONS} max sessions, ${this.sessionTimeout / 1000 / 60}min timeout`);
|
||||||
console.log(`Health check: ${endpoints.health}`);
|
console.log(`Health check: ${endpoints.health}`);
|
||||||
console.log(`MCP endpoint: ${endpoints.mcp}`);
|
console.log(`MCP endpoint: ${endpoints.mcp}`);
|
||||||
|
console.log(`SSE endpoint: ${baseUrl}/sse (legacy clients)`);
|
||||||
if (isProduction) {
|
if (isProduction) {
|
||||||
console.log('🔒 Running in PRODUCTION mode - enhanced security enabled');
|
console.log('🔒 Running in PRODUCTION mode - enhanced security enabled');
|
||||||
}
|
}
|
||||||
@@ -1056,16 +1094,6 @@ class SingleSessionHTTPServer {
|
|||||||
logger_1.logger.warn(`Error closing transport for session ${sessionId}:`, error);
|
logger_1.logger.warn(`Error closing transport for session ${sessionId}:`, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.session) {
|
|
||||||
try {
|
|
||||||
await this.session.transport.close();
|
|
||||||
logger_1.logger.info('Legacy session closed');
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
logger_1.logger.warn('Error closing legacy session:', error);
|
|
||||||
}
|
|
||||||
this.session = null;
|
|
||||||
}
|
|
||||||
if (this.expressServer) {
|
if (this.expressServer) {
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
this.expressServer.close(() => {
|
this.expressServer.close(() => {
|
||||||
@@ -1085,22 +1113,8 @@ class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
getSessionInfo() {
|
getSessionInfo() {
|
||||||
const metrics = this.getSessionMetrics();
|
const metrics = this.getSessionMetrics();
|
||||||
if (!this.session) {
|
|
||||||
return {
|
|
||||||
active: false,
|
|
||||||
sessions: {
|
|
||||||
total: metrics.totalSessions,
|
|
||||||
active: metrics.activeSessions,
|
|
||||||
expired: metrics.expiredSessions,
|
|
||||||
max: MAX_SESSIONS,
|
|
||||||
sessionIds: Object.keys(this.transports)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
active: true,
|
active: metrics.activeSessions > 0,
|
||||||
sessionId: this.session.sessionId,
|
|
||||||
age: Date.now() - this.session.lastAccess.getTime(),
|
|
||||||
sessions: {
|
sessions: {
|
||||||
total: metrics.totalSessions,
|
total: metrics.totalSessions,
|
||||||
active: metrics.activeSessions,
|
active: metrics.activeSessions,
|
||||||
|
|||||||
2
dist/http-server-single-session.js.map
vendored
2
dist/http-server-single-session.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/index.d.ts
vendored
1
dist/index.d.ts
vendored
@@ -5,6 +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, 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
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;AAG/B,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;AAQnB,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-engine.d.ts
vendored
2
dist/mcp-engine.d.ts
vendored
@@ -1,6 +1,7 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { InstanceContext } from './types/instance-context';
|
import { InstanceContext } from './types/instance-context';
|
||||||
import { SessionState } from './types/session-state';
|
import { SessionState } from './types/session-state';
|
||||||
|
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||||
export interface EngineHealth {
|
export interface EngineHealth {
|
||||||
status: 'healthy' | 'unhealthy';
|
status: 'healthy' | 'unhealthy';
|
||||||
uptime: number;
|
uptime: number;
|
||||||
@@ -15,6 +16,7 @@ export interface EngineHealth {
|
|||||||
export interface EngineOptions {
|
export interface EngineOptions {
|
||||||
sessionTimeout?: number;
|
sessionTimeout?: number;
|
||||||
logLevel?: 'error' | 'warn' | 'info' | 'debug';
|
logLevel?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
}
|
}
|
||||||
export declare class N8NMCPEngine {
|
export declare class N8NMCPEngine {
|
||||||
private server;
|
private server;
|
||||||
|
|||||||
2
dist/mcp-engine.d.ts.map
vendored
2
dist/mcp-engine.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"mcp-engine.d.ts","sourceRoot":"","sources":["../src/mcp-engine.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAAO;gBAEZ,OAAO,GAAE,aAAkB;IA8BjC,cAAc,CAClB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;IAkBV,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAgC1C,cAAc,IAAI;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;IAoBvE,kBAAkB,IAAI,YAAY,EAAE;IAwBpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;IAiB/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IASzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AA2CD,eAAe,YAAY,CAAC"}
|
{"version":3,"file":"mcp-engine.d.ts","sourceRoot":"","sources":["../src/mcp-engine.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAAO;gBAEZ,OAAO,GAAE,aAAkB;IAgCjC,cAAc,CAClB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,IAAI,CAAC;IAkBV,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC;IAgC1C,cAAc,IAAI;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE;IAoBvE,kBAAkB,IAAI,YAAY,EAAE;IAwBpC,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,MAAM;IAiB/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IASzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AA2CD,eAAe,YAAY,CAAC"}
|
||||||
4
dist/mcp-engine.js
vendored
4
dist/mcp-engine.js
vendored
@@ -5,7 +5,9 @@ const http_server_single_session_1 = require("./http-server-single-session");
|
|||||||
const logger_1 = require("./utils/logger");
|
const logger_1 = require("./utils/logger");
|
||||||
class N8NMCPEngine {
|
class N8NMCPEngine {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.server = new http_server_single_session_1.SingleSessionHTTPServer();
|
this.server = new http_server_single_session_1.SingleSessionHTTPServer({
|
||||||
|
generateWorkflowHandler: options.generateWorkflowHandler,
|
||||||
|
});
|
||||||
this.startTime = new Date();
|
this.startTime = new Date();
|
||||||
if (options.logLevel) {
|
if (options.logLevel) {
|
||||||
process.env.LOG_LEVEL = options.logLevel;
|
process.env.LOG_LEVEL = options.logLevel;
|
||||||
|
|||||||
2
dist/mcp-engine.js.map
vendored
2
dist/mcp-engine.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"mcp-engine.js","sourceRoot":"","sources":["../src/mcp-engine.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"mcp-engine.js","sourceRoot":"","sources":["../src/mcp-engine.ts"],"names":[],"mappings":";;;AAQA,6EAAuE;AACvE,2CAAwC;AAuBxC,MAAa,YAAY;IAIvB,YAAY,UAAyB,EAAE;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,oDAAuB,CAAC;YACxC,uBAAuB,EAAE,OAAO,CAAC,uBAAuB;SACzD,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAE5B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC3C,CAAC;IACH,CAAC;IAuBD,KAAK,CAAC,cAAc,CAClB,GAAY,EACZ,GAAa,EACb,eAAiC;QAEjC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,eAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAWD,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YACjD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAE1C,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;gBAClE,aAAa,EAAE,WAAW,CAAC,MAAM;gBACjC,WAAW,EAAE;oBACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;oBACpD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;oBACtD,IAAI,EAAE,IAAI;iBACX;gBACD,OAAO,EAAE,QAAQ;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,eAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC5C,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,CAAC;gBACT,aAAa,EAAE,KAAK;gBACpB,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;gBAC9C,OAAO,EAAE,QAAQ;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAMD,cAAc;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;IACtC,CAAC;IAkBD,kBAAkB;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,eAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;IAC1C,CAAC;IAkBD,mBAAmB,CAAC,QAAwB;QAC1C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,eAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAWD,KAAK,CAAC,QAAQ;QACZ,eAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAMD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;CACF;AAnKD,oCAmKC;AA2CD,kBAAe,YAAY,CAAC"}
|
||||||
1
dist/mcp/handlers-n8n-manager.d.ts
vendored
1
dist/mcp/handlers-n8n-manager.d.ts
vendored
@@ -26,6 +26,7 @@ export declare function handleDiagnostic(request: any, context?: InstanceContext
|
|||||||
export declare function handleWorkflowVersions(args: unknown, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleWorkflowVersions(args: unknown, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
export declare function handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
export declare function handleTriggerWebhookWorkflow(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleTriggerWebhookWorkflow(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
|
export declare function tryParseJson(val: unknown): unknown;
|
||||||
export declare function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
export declare function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
|
||||||
|
|||||||
2
dist/mcp/handlers-n8n-manager.d.ts.map
vendored
2
dist/mcp/handlers-n8n-manager.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}
|
||||||
19
dist/mcp/handlers-n8n-manager.js
vendored
19
dist/mcp/handlers-n8n-manager.js
vendored
@@ -56,6 +56,7 @@ exports.handleDiagnostic = handleDiagnostic;
|
|||||||
exports.handleWorkflowVersions = handleWorkflowVersions;
|
exports.handleWorkflowVersions = handleWorkflowVersions;
|
||||||
exports.handleDeployTemplate = handleDeployTemplate;
|
exports.handleDeployTemplate = handleDeployTemplate;
|
||||||
exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow;
|
exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow;
|
||||||
|
exports.tryParseJson = tryParseJson;
|
||||||
exports.handleCreateTable = handleCreateTable;
|
exports.handleCreateTable = handleCreateTable;
|
||||||
exports.handleListTables = handleListTables;
|
exports.handleListTables = handleListTables;
|
||||||
exports.handleGetTable = handleGetTable;
|
exports.handleGetTable = handleGetTable;
|
||||||
@@ -518,6 +519,24 @@ async function handleUpdateWorkflow(args, repository, context) {
|
|||||||
if (updateData.nodes || updateData.connections) {
|
if (updateData.nodes || updateData.connections) {
|
||||||
const current = await client.getWorkflow(id);
|
const current = await client.getWorkflow(id);
|
||||||
workflowBefore = JSON.parse(JSON.stringify(current));
|
workflowBefore = JSON.parse(JSON.stringify(current));
|
||||||
|
if (updateData.nodes && current.nodes) {
|
||||||
|
const currentById = new Map();
|
||||||
|
const currentByName = new Map();
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (createBackup !== false) {
|
if (createBackup !== false) {
|
||||||
try {
|
try {
|
||||||
const versioningService = new workflow_versioning_service_1.WorkflowVersioningService(repository, client);
|
const versioningService = new workflow_versioning_service_1.WorkflowVersioningService(repository, client);
|
||||||
|
|||||||
2
dist/mcp/handlers-n8n-manager.js.map
vendored
2
dist/mcp/handlers-n8n-manager.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/mcp/handlers-workflow-diff.d.ts.map
vendored
2
dist/mcp/handlers-workflow-diff.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"handlers-workflow-diff.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-workflow-diff.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAkF7D,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,eAAe,CAAC,CAib1B"}
|
{"version":3,"file":"handlers-workflow-diff.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-workflow-diff.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAoF7D,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,eAAe,CAAC,CAib1B"}
|
||||||
14
dist/mcp/handlers-workflow-diff.js
vendored
14
dist/mcp/handlers-workflow-diff.js
vendored
@@ -51,17 +51,19 @@ function getValidator(repository) {
|
|||||||
return cachedValidator;
|
return cachedValidator;
|
||||||
}
|
}
|
||||||
const NODE_TARGETING_OPERATIONS = new Set([
|
const NODE_TARGETING_OPERATIONS = new Set([
|
||||||
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
|
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode', 'patchNodeField'
|
||||||
]);
|
]);
|
||||||
const workflowDiffSchema = zod_1.z.object({
|
const workflowDiffSchema = zod_1.z.object({
|
||||||
id: zod_1.z.string(),
|
id: zod_1.z.string(),
|
||||||
operations: zod_1.z.array(zod_1.z.object({
|
operations: zod_1.z.preprocess(handlers_n8n_manager_1.tryParseJson, zod_1.z.array(zod_1.z.object({
|
||||||
type: zod_1.z.string(),
|
type: zod_1.z.string(),
|
||||||
description: zod_1.z.string().optional(),
|
description: zod_1.z.string().optional(),
|
||||||
node: zod_1.z.any().optional(),
|
node: zod_1.z.any().optional(),
|
||||||
nodeId: zod_1.z.string().optional(),
|
nodeId: zod_1.z.string().optional(),
|
||||||
nodeName: zod_1.z.string().optional(),
|
nodeName: zod_1.z.string().optional(),
|
||||||
updates: zod_1.z.any().optional(),
|
updates: zod_1.z.any().optional(),
|
||||||
|
fieldPath: zod_1.z.string().optional(),
|
||||||
|
patches: zod_1.z.any().optional(),
|
||||||
position: zod_1.z.tuple([zod_1.z.number(), zod_1.z.number()]).optional(),
|
position: zod_1.z.tuple([zod_1.z.number(), zod_1.z.number()]).optional(),
|
||||||
source: zod_1.z.string().optional(),
|
source: zod_1.z.string().optional(),
|
||||||
target: zod_1.z.string().optional(),
|
target: zod_1.z.string().optional(),
|
||||||
@@ -93,7 +95,7 @@ const workflowDiffSchema = zod_1.z.object({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return op;
|
return op;
|
||||||
})),
|
}))),
|
||||||
validateOnly: zod_1.z.boolean().optional(),
|
validateOnly: zod_1.z.boolean().optional(),
|
||||||
continueOnError: zod_1.z.boolean().optional(),
|
continueOnError: zod_1.z.boolean().optional(),
|
||||||
createBackup: zod_1.z.boolean().optional(),
|
createBackup: zod_1.z.boolean().optional(),
|
||||||
@@ -506,6 +508,8 @@ function inferIntentFromOperations(operations) {
|
|||||||
return `Remove node ${op.nodeName || op.nodeId || ''}`.trim();
|
return `Remove node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
case 'updateNode':
|
case 'updateNode':
|
||||||
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
|
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
|
case 'patchNodeField':
|
||||||
|
return `Patch field on node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
case 'addConnection':
|
case 'addConnection':
|
||||||
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
|
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
|
||||||
case 'removeConnection':
|
case 'removeConnection':
|
||||||
@@ -538,6 +542,10 @@ function inferIntentFromOperations(operations) {
|
|||||||
const count = opTypes.filter((t) => t === 'updateNode').length;
|
const count = opTypes.filter((t) => t === 'updateNode').length;
|
||||||
summary.push(`update ${count} node${count > 1 ? 's' : ''}`);
|
summary.push(`update ${count} node${count > 1 ? 's' : ''}`);
|
||||||
}
|
}
|
||||||
|
if (typeSet.has('patchNodeField')) {
|
||||||
|
const count = opTypes.filter((t) => t === 'patchNodeField').length;
|
||||||
|
summary.push(`patch ${count} field${count > 1 ? 's' : ''}`);
|
||||||
|
}
|
||||||
if (typeSet.has('addConnection') || typeSet.has('rewireConnection')) {
|
if (typeSet.has('addConnection') || typeSet.has('rewireConnection')) {
|
||||||
summary.push('modify connections');
|
summary.push('modify connections');
|
||||||
}
|
}
|
||||||
|
|||||||
2
dist/mcp/handlers-workflow-diff.js.map
vendored
2
dist/mcp/handlers-workflow-diff.js.map
vendored
File diff suppressed because one or more lines are too long
11
dist/mcp/server.d.ts
vendored
11
dist/mcp/server.d.ts
vendored
@@ -1,5 +1,9 @@
|
|||||||
import { InstanceContext } from '../types/instance-context';
|
import { InstanceContext } from '../types/instance-context';
|
||||||
|
import { GenerateWorkflowHandler } from '../types/generate-workflow';
|
||||||
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
|
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
|
||||||
|
interface MCPServerOptions {
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
|
}
|
||||||
export declare class N8NDocumentationMCPServer {
|
export declare class N8NDocumentationMCPServer {
|
||||||
private server;
|
private server;
|
||||||
private db;
|
private db;
|
||||||
@@ -16,7 +20,8 @@ export declare class N8NDocumentationMCPServer {
|
|||||||
private useSharedDatabase;
|
private useSharedDatabase;
|
||||||
private sharedDbState;
|
private sharedDbState;
|
||||||
private isShutdown;
|
private isShutdown;
|
||||||
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger);
|
private generateWorkflowHandler?;
|
||||||
|
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger, options?: MCPServerOptions);
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
private initializeDatabase;
|
private initializeDatabase;
|
||||||
private initializeInMemorySchema;
|
private initializeInMemorySchema;
|
||||||
@@ -46,6 +51,7 @@ export declare class N8NDocumentationMCPServer {
|
|||||||
private getNodeDocumentation;
|
private getNodeDocumentation;
|
||||||
private safeJsonParse;
|
private safeJsonParse;
|
||||||
private getDatabaseStatistics;
|
private getDatabaseStatistics;
|
||||||
|
private buildOperationsTree;
|
||||||
private getNodeEssentials;
|
private getNodeEssentials;
|
||||||
private getNode;
|
private getNode;
|
||||||
private handleInfoMode;
|
private handleInfoMode;
|
||||||
@@ -74,6 +80,8 @@ export declare class N8NDocumentationMCPServer {
|
|||||||
private listNodeTemplates;
|
private listNodeTemplates;
|
||||||
private getTemplate;
|
private getTemplate;
|
||||||
private searchTemplates;
|
private searchTemplates;
|
||||||
|
private workflowPatternsCache;
|
||||||
|
private getWorkflowPatterns;
|
||||||
private getTemplatesForTask;
|
private getTemplatesForTask;
|
||||||
private searchTemplatesByMetadata;
|
private searchTemplatesByMetadata;
|
||||||
private getTaskDescription;
|
private getTaskDescription;
|
||||||
@@ -83,4 +91,5 @@ export declare class N8NDocumentationMCPServer {
|
|||||||
run(): Promise<void>;
|
run(): Promise<void>;
|
||||||
shutdown(): Promise<void>;
|
shutdown(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
export {};
|
||||||
//# sourceMappingURL=server.d.ts.map
|
//# sourceMappingURL=server.d.ts.map
|
||||||
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":"AA0CA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAmGnE,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAgC;IAC1C,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,qBAAqB,CAAsB;IACnD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,iBAAiB,CAAkB;IAC3C,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,UAAU,CAAkB;gBAExB,eAAe,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,gBAAgB;IA8GvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA+Cd,kBAAkB;YAiDlB,wBAAwB;IA0BtC,OAAO,CAAC,kBAAkB;YA6CZ,iBAAiB;IAa/B,OAAO,CAAC,eAAe,CAAkB;YAE3B,sBAAsB;IAgDpC,OAAO,CAAC,gBAAgB;IAqCxB,OAAO,CAAC,aAAa;IA0XrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IA0E1B,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,2BAA2B;YA8VrB,SAAS;YA2DT,WAAW;YAkFX,WAAW;YA0CX,cAAc;YA8Md,gBAAgB;IAqD9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IA2L7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;IAuFlC,OAAO,CAAC,aAAa;YAQP,qBAAqB;YAwDrB,iBAAiB;YAiKjB,OAAO;YAgDP,cAAc;YAwFd,iBAAiB;IAqC/B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,kBAAkB;IAiC1B,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,0BAA0B;IAgClC,OAAO,CAAC,4BAA4B;YAKtB,oBAAoB;IAsDlC,OAAO,CAAC,gBAAgB;YAiBV,SAAS;YA6CT,kBAAkB;YAqElB,uBAAuB;YAsDvB,iBAAiB;IAqE/B,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,uBAAuB;IA4D/B,OAAO,CAAC,wBAAwB;IAkChC,OAAO,CAAC,iBAAiB;YAoDX,mBAAmB;YAoEnB,qBAAqB;IAS7B,OAAO,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YAS9B,aAAa;YAcb,iBAAiB;YAoBjB,WAAW;YAwBX,eAAe;YAqBf,mBAAmB;YAwBnB,yBAAyB;IA4CvC,OAAO,CAAC,kBAAkB;YAiBZ,gBAAgB;YA6HhB,2BAA2B;YAiE3B,2BAA2B;IAyEnC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAgEhC"}
|
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
||||||
186
dist/mcp/server.js
vendored
186
dist/mcp/server.js
vendored
@@ -72,7 +72,7 @@ const protocol_version_1 = require("../utils/protocol-version");
|
|||||||
const telemetry_1 = require("../telemetry");
|
const telemetry_1 = require("../telemetry");
|
||||||
const startup_checkpoints_1 = require("../telemetry/startup-checkpoints");
|
const startup_checkpoints_1 = require("../telemetry/startup-checkpoints");
|
||||||
class N8NDocumentationMCPServer {
|
class N8NDocumentationMCPServer {
|
||||||
constructor(instanceContext, earlyLogger) {
|
constructor(instanceContext, earlyLogger, options) {
|
||||||
this.db = null;
|
this.db = null;
|
||||||
this.repository = null;
|
this.repository = null;
|
||||||
this.templateService = null;
|
this.templateService = null;
|
||||||
@@ -86,8 +86,10 @@ class N8NDocumentationMCPServer {
|
|||||||
this.sharedDbState = null;
|
this.sharedDbState = null;
|
||||||
this.isShutdown = false;
|
this.isShutdown = false;
|
||||||
this.dbHealthChecked = false;
|
this.dbHealthChecked = false;
|
||||||
|
this.workflowPatternsCache = null;
|
||||||
this.instanceContext = instanceContext;
|
this.instanceContext = instanceContext;
|
||||||
this.earlyLogger = earlyLogger || null;
|
this.earlyLogger = earlyLogger || null;
|
||||||
|
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||||
const envDbPath = process.env.NODE_DB_PATH;
|
const envDbPath = process.env.NODE_DB_PATH;
|
||||||
let dbPath = null;
|
let dbPath = null;
|
||||||
let possiblePaths = [];
|
let possiblePaths = [];
|
||||||
@@ -499,6 +501,9 @@ class N8NDocumentationMCPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
|
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
|
||||||
|
if (processedArgs) {
|
||||||
|
processedArgs = JSON.parse(JSON.stringify(processedArgs));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs });
|
logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs });
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@@ -931,6 +936,7 @@ class N8NDocumentationMCPServer {
|
|||||||
return this.searchNodes(args.query, limit, {
|
return this.searchNodes(args.query, limit, {
|
||||||
mode: args.mode,
|
mode: args.mode,
|
||||||
includeExamples: args.includeExamples,
|
includeExamples: args.includeExamples,
|
||||||
|
includeOperations: args.includeOperations,
|
||||||
source: args.source
|
source: args.source
|
||||||
});
|
});
|
||||||
case 'get_node':
|
case 'get_node':
|
||||||
@@ -1022,6 +1028,8 @@ class N8NDocumentationMCPServer {
|
|||||||
requiredService: args.requiredService,
|
requiredService: args.requiredService,
|
||||||
targetAudience: args.targetAudience
|
targetAudience: args.targetAudience
|
||||||
}, searchLimit, searchOffset);
|
}, searchLimit, searchOffset);
|
||||||
|
case 'patterns':
|
||||||
|
return this.getWorkflowPatterns(args.task, searchLimit);
|
||||||
case 'keyword':
|
case 'keyword':
|
||||||
default:
|
default:
|
||||||
if (!args.query) {
|
if (!args.query) {
|
||||||
@@ -1132,6 +1140,44 @@ class N8NDocumentationMCPServer {
|
|||||||
throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`);
|
throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 = {
|
||||||
|
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(args, ctx, helpers);
|
||||||
|
return result ?? { success: false, error: 'Handler returned no result' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
const message = err instanceof Error ? err.message : String(err);
|
||||||
|
return { success: false, error: message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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:
|
default:
|
||||||
throw new Error(`Unknown tool: ${name}`);
|
throw new Error(`Unknown tool: ${name}`);
|
||||||
}
|
}
|
||||||
@@ -1270,7 +1316,7 @@ class N8NDocumentationMCPServer {
|
|||||||
return { query, results: [], totalCount: 0 };
|
return { query, results: [], totalCount: 0 };
|
||||||
}
|
}
|
||||||
if (mode === 'FUZZY') {
|
if (mode === 'FUZZY') {
|
||||||
return this.searchNodesFuzzy(cleanedQuery, limit);
|
return this.searchNodesFuzzy(cleanedQuery, limit, { includeOperations: options?.includeOperations });
|
||||||
}
|
}
|
||||||
let ftsQuery;
|
let ftsQuery;
|
||||||
if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) {
|
if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) {
|
||||||
@@ -1338,7 +1384,7 @@ class N8NDocumentationMCPServer {
|
|||||||
const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest');
|
const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest');
|
||||||
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
|
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
|
||||||
logger_1.logger.debug('FTS missed HTTP Request node, augmenting with LIKE search');
|
logger_1.logger.debug('FTS missed HTTP Request node, augmenting with LIKE search');
|
||||||
return this.searchNodesLIKE(query, limit);
|
return this.searchNodesLIKE(query, limit, options);
|
||||||
}
|
}
|
||||||
const result = {
|
const result = {
|
||||||
query,
|
query,
|
||||||
@@ -1362,6 +1408,12 @@ class N8NDocumentationMCPServer {
|
|||||||
nodeResult.npmDownloads = node.npm_downloads;
|
nodeResult.npmDownloads = node.npm_downloads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options?.includeOperations) {
|
||||||
|
const opsTree = this.buildOperationsTree(node.operations);
|
||||||
|
if (opsTree) {
|
||||||
|
nodeResult.operationsTree = opsTree;
|
||||||
|
}
|
||||||
|
}
|
||||||
return nodeResult;
|
return nodeResult;
|
||||||
}),
|
}),
|
||||||
totalCount: scoredNodes.length
|
totalCount: scoredNodes.length
|
||||||
@@ -1412,7 +1464,7 @@ class N8NDocumentationMCPServer {
|
|||||||
return this.searchNodesLIKE(query, limit);
|
return this.searchNodesLIKE(query, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async searchNodesFuzzy(query, limit) {
|
async searchNodesFuzzy(query, limit, options) {
|
||||||
if (!this.db)
|
if (!this.db)
|
||||||
throw new Error('Database not initialized');
|
throw new Error('Database not initialized');
|
||||||
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
|
||||||
@@ -1440,14 +1492,23 @@ class N8NDocumentationMCPServer {
|
|||||||
return {
|
return {
|
||||||
query,
|
query,
|
||||||
mode: 'FUZZY',
|
mode: 'FUZZY',
|
||||||
results: matchingNodes.map(node => ({
|
results: matchingNodes.map(node => {
|
||||||
nodeType: node.node_type,
|
const nodeResult = {
|
||||||
workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type),
|
nodeType: node.node_type,
|
||||||
displayName: node.display_name,
|
workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type),
|
||||||
description: node.description,
|
displayName: node.display_name,
|
||||||
category: node.category,
|
description: node.description,
|
||||||
package: node.package_name
|
category: node.category,
|
||||||
})),
|
package: node.package_name
|
||||||
|
};
|
||||||
|
if (options?.includeOperations) {
|
||||||
|
const opsTree = this.buildOperationsTree(node.operations);
|
||||||
|
if (opsTree) {
|
||||||
|
nodeResult.operationsTree = opsTree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeResult;
|
||||||
|
}),
|
||||||
totalCount: matchingNodes.length
|
totalCount: matchingNodes.length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1568,6 +1629,12 @@ class N8NDocumentationMCPServer {
|
|||||||
nodeResult.npmDownloads = node.npm_downloads;
|
nodeResult.npmDownloads = node.npm_downloads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options?.includeOperations) {
|
||||||
|
const opsTree = this.buildOperationsTree(node.operations);
|
||||||
|
if (opsTree) {
|
||||||
|
nodeResult.operationsTree = opsTree;
|
||||||
|
}
|
||||||
|
}
|
||||||
return nodeResult;
|
return nodeResult;
|
||||||
}),
|
}),
|
||||||
totalCount: rankedNodes.length
|
totalCount: rankedNodes.length
|
||||||
@@ -1635,6 +1702,12 @@ class N8NDocumentationMCPServer {
|
|||||||
nodeResult.npmDownloads = node.npm_downloads;
|
nodeResult.npmDownloads = node.npm_downloads;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options?.includeOperations) {
|
||||||
|
const opsTree = this.buildOperationsTree(node.operations);
|
||||||
|
if (opsTree) {
|
||||||
|
nodeResult.operationsTree = opsTree;
|
||||||
|
}
|
||||||
|
}
|
||||||
return nodeResult;
|
return nodeResult;
|
||||||
}),
|
}),
|
||||||
totalCount: rankedNodes.length
|
totalCount: rankedNodes.length
|
||||||
@@ -1938,6 +2011,47 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
buildOperationsTree(operationsRaw) {
|
||||||
|
if (!operationsRaw)
|
||||||
|
return undefined;
|
||||||
|
let ops;
|
||||||
|
if (typeof operationsRaw === 'string') {
|
||||||
|
try {
|
||||||
|
ops = JSON.parse(operationsRaw);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Array.isArray(operationsRaw)) {
|
||||||
|
ops = operationsRaw;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(ops) || ops.length === 0)
|
||||||
|
return undefined;
|
||||||
|
const byResource = new Map();
|
||||||
|
for (const op of ops) {
|
||||||
|
const resource = op.resource || 'default';
|
||||||
|
const opName = op.name || op.operation;
|
||||||
|
if (!opName)
|
||||||
|
continue;
|
||||||
|
if (!byResource.has(resource)) {
|
||||||
|
byResource.set(resource, []);
|
||||||
|
}
|
||||||
|
const list = byResource.get(resource);
|
||||||
|
if (!list.includes(opName)) {
|
||||||
|
list.push(opName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (byResource.size === 0)
|
||||||
|
return undefined;
|
||||||
|
return Array.from(byResource.entries()).map(([resource, operations]) => ({
|
||||||
|
resource,
|
||||||
|
operations
|
||||||
|
}));
|
||||||
|
}
|
||||||
async getNodeEssentials(nodeType, includeExamples) {
|
async getNodeEssentials(nodeType, includeExamples) {
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
if (!this.repository)
|
if (!this.repository)
|
||||||
@@ -2795,6 +2909,54 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
tip: `Found ${result.total} templates matching "${query}". Showing ${result.items.length}.`
|
tip: `Found ${result.total} templates matching "${query}". Showing ${result.items.length}.`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
getWorkflowPatterns(category, limit = 10) {
|
||||||
|
if (!this.workflowPatternsCache) {
|
||||||
|
try {
|
||||||
|
const patternsPath = path_1.default.join(__dirname, '..', '..', 'data', 'workflow-patterns.json');
|
||||||
|
if ((0, fs_1.existsSync)(patternsPath)) {
|
||||||
|
this.workflowPatternsCache = JSON.parse((0, fs_1.readFileSync)(patternsPath, 'utf-8'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return { error: 'Workflow patterns not generated yet. Run: npm run mine:patterns' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return { error: `Failed to load workflow patterns: ${e instanceof Error ? e.message : String(e)}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const patterns = this.workflowPatternsCache;
|
||||||
|
if (category) {
|
||||||
|
const categoryData = patterns.categories[category];
|
||||||
|
if (!categoryData) {
|
||||||
|
const available = Object.keys(patterns.categories);
|
||||||
|
return { error: `Unknown category "${category}". Available: ${available.join(', ')}` };
|
||||||
|
}
|
||||||
|
const MAX_CHAINS = 5;
|
||||||
|
return {
|
||||||
|
category,
|
||||||
|
templateCount: categoryData.templateCount,
|
||||||
|
pattern: categoryData.pattern,
|
||||||
|
nodes: categoryData.nodes?.slice(0, limit).map(n => ({
|
||||||
|
type: n.type, freq: n.frequency, role: n.role
|
||||||
|
})),
|
||||||
|
chains: categoryData.commonChains?.slice(0, MAX_CHAINS).map(c => ({
|
||||||
|
path: c.chain.map(t => t.split('.').pop() ?? t), count: c.count, freq: c.frequency
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const overview = Object.entries(patterns.categories).map(([name, data]) => ({
|
||||||
|
category: name,
|
||||||
|
templateCount: data.templateCount,
|
||||||
|
pattern: data.pattern,
|
||||||
|
topNodes: data.nodes?.slice(0, 5).map(n => n.displayName || n.type),
|
||||||
|
}));
|
||||||
|
return {
|
||||||
|
templateCount: patterns.templateCount,
|
||||||
|
generatedAt: patterns.generatedAt,
|
||||||
|
categories: overview,
|
||||||
|
tip: 'Use search_templates({searchMode: "patterns", task: "category_name"}) for full pattern data with nodes, chains, and tips.',
|
||||||
|
};
|
||||||
|
}
|
||||||
async getTemplatesForTask(task, limit = 10, offset = 0) {
|
async getTemplatesForTask(task, limit = 10, offset = 0) {
|
||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
if (!this.templateService)
|
if (!this.templateService)
|
||||||
|
|||||||
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
10
dist/mcp/stdio-wrapper.js
vendored
10
dist/mcp/stdio-wrapper.js
vendored
@@ -29,6 +29,16 @@ console.table = () => { };
|
|||||||
console.clear = () => { };
|
console.clear = () => { };
|
||||||
console.count = () => { };
|
console.count = () => { };
|
||||||
console.countReset = () => { };
|
console.countReset = () => { };
|
||||||
|
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
||||||
|
const stderrWrite = process.stderr.write.bind(process.stderr);
|
||||||
|
process.stdout.write = function (chunk, encodingOrCallback, callback) {
|
||||||
|
const str = typeof chunk === 'string' ? chunk : chunk.toString();
|
||||||
|
const trimmed = str.trimStart();
|
||||||
|
if (trimmed.startsWith('{') && trimmed.includes('"jsonrpc"')) {
|
||||||
|
return originalStdoutWrite(chunk, encodingOrCallback, callback);
|
||||||
|
}
|
||||||
|
return stderrWrite(chunk, encodingOrCallback, callback);
|
||||||
|
};
|
||||||
const server_1 = require("./server");
|
const server_1 = require("./server");
|
||||||
let server = null;
|
let server = null;
|
||||||
async function main() {
|
async function main() {
|
||||||
|
|||||||
2
dist/mcp/stdio-wrapper.js.map
vendored
2
dist/mcp/stdio-wrapper.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"stdio-wrapper.js","sourceRoot":"","sources":["../../src/mcp/stdio-wrapper.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"stdio-wrapper.js","sourceRoot":"","sources":["../../src/mcp/stdio-wrapper.ts"],"names":[],"mappings":"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"}
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"search-nodes.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/discovery/search-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,cAAc,EAAE,iBAiE5B,CAAC"}
|
{"version":3,"file":"search-nodes.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/discovery/search-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,cAAc,EAAE,iBA+D5B,CAAC"}
|
||||||
16
dist/mcp/tool-docs/discovery/search-nodes.js
vendored
16
dist/mcp/tool-docs/discovery/search-nodes.js
vendored
@@ -6,7 +6,7 @@ exports.searchNodesDoc = {
|
|||||||
category: 'discovery',
|
category: 'discovery',
|
||||||
essentials: {
|
essentials: {
|
||||||
description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.',
|
description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.',
|
||||||
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples'],
|
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples', 'includeOperations'],
|
||||||
example: 'search_nodes({query: "webhook"})',
|
example: 'search_nodes({query: "webhook"})',
|
||||||
performance: '<20ms even for complex queries',
|
performance: '<20ms even for complex queries',
|
||||||
tips: [
|
tips: [
|
||||||
@@ -15,7 +15,8 @@ exports.searchNodesDoc = {
|
|||||||
'FUZZY mode: Handles typos and spelling errors',
|
'FUZZY mode: Handles typos and spelling errors',
|
||||||
'Use quotes for exact phrases: "google sheets"',
|
'Use quotes for exact phrases: "google sheets"',
|
||||||
'Use source="community" to search only community nodes',
|
'Use source="community" to search only community nodes',
|
||||||
'Use source="verified" for verified community nodes only'
|
'Use source="verified" for verified community nodes only',
|
||||||
|
'Use includeOperations=true to get resource/operation trees without a separate get_node call'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
full: {
|
full: {
|
||||||
@@ -25,20 +26,17 @@ exports.searchNodesDoc = {
|
|||||||
limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false },
|
limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false },
|
||||||
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
|
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
|
||||||
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
|
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
|
||||||
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false }
|
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false },
|
||||||
|
includeOperations: { type: 'boolean', description: 'Include resource/operation tree per node. Default: false. Adds ~100-300 tokens per result but saves a get_node round-trip. Only returned for nodes with resource/operation patterns — trigger nodes and freeform nodes (Code, HTTP Request) omit this field.', required: false }
|
||||||
},
|
},
|
||||||
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
|
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
|
||||||
examples: [
|
examples: [
|
||||||
'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
|
'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
|
||||||
'search_nodes({query: "database"}) - Returns MySQL, Postgres, MongoDB, Redis, etc.',
|
|
||||||
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
|
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
|
||||||
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
|
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
|
||||||
'search_nodes({query: "http api"}) - Finds HTTP Request, GraphQL, REST nodes',
|
|
||||||
'search_nodes({query: "transform data"}) - Finds Set, Code, Function, Item Lists nodes',
|
|
||||||
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
|
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
|
||||||
'search_nodes({query: "pdf", source: "verified"}) - Find verified community PDF nodes',
|
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples',
|
||||||
'search_nodes({query: "brightdata"}) - Find BrightData community node',
|
'search_nodes({query: "slack", includeOperations: true}) - Get Slack with resource/operation tree (7 resources, 44 ops)'
|
||||||
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples'
|
|
||||||
],
|
],
|
||||||
useCases: [
|
useCases: [
|
||||||
'Finding nodes when you know partial names',
|
'Finding nodes when you know partial names',
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"search-nodes.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/discovery/search-nodes.ts"],"names":[],"mappings":";;;AAEa,QAAA,cAAc,GAAsB;IAC/C,IAAI,EAAE,cAAc;IACpB,QAAQ,EAAE,WAAW;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,kPAAkP;QAC/P,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,CAAC;QACtE,OAAO,EAAE,kCAAkC;QAC3C,WAAW,EAAE,gCAAgC;QAC7C,IAAI,EAAE;YACJ,4CAA4C;YAC5C,sCAAsC;YACtC,+CAA+C;YAC/C,+CAA+C;YAC/C,uDAAuD;YACvD,yDAAyD;SAC1D;KACF;IACD,IAAI,EAAE;QACJ,WAAW,EAAE,qcAAqc;QACld,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC5H,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kDAAkD,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC3G,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oGAAoG,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC5J,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kKAAkK,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC5N,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,sIAAsI,EAAE,QAAQ,EAAE,KAAK,EAAE;SAC3M;QACD,OAAO,EAAE,yTAAyT;QAClU,QAAQ,EAAE;YACR,uEAAuE;YACvE,mFAAmF;YACnF,2EAA2E;YAC3E,yEAAyE;YACzE,6EAA6E;YAC7E,uFAAuF;YACvF,wFAAwF;YACxF,sFAAsF;YACtF,sEAAsE;YACtE,0FAA0F;SAC3F;QACD,QAAQ,EAAE;YACR,2CAA2C;YAC3C,6EAA6E;YAC7E,mCAAmC;YACnC,6EAA6E;YAC7E,0DAA0D;YAC1D,qDAAqD;SACtD;QACD,WAAW,EAAE,uFAAuF;QACpG,aAAa,EAAE;YACb,iDAAiD;YACjD,qDAAqD;YACrD,2CAA2C;YAC3C,oDAAoD;YACpD,wEAAwE;YACxE,wDAAwD;SACzD;QACD,QAAQ,EAAE;YACR,sEAAsE;YACtE,8EAA8E;YAC9E,4CAA4C;YAC5C,2EAA2E;YAC3E,yEAAyE;SAC1E;QACD,YAAY,EAAE,CAAC,mCAAmC,EAAE,4CAA4C,EAAE,uCAAuC,CAAC;KAC3I;CACF,CAAC"}
|
{"version":3,"file":"search-nodes.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/discovery/search-nodes.ts"],"names":[],"mappings":";;;AAEa,QAAA,cAAc,GAAsB;IAC/C,IAAI,EAAE,cAAc;IACpB,QAAQ,EAAE,WAAW;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,kPAAkP;QAC/P,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,mBAAmB,CAAC;QAC3F,OAAO,EAAE,kCAAkC;QAC3C,WAAW,EAAE,gCAAgC;QAC7C,IAAI,EAAE;YACJ,4CAA4C;YAC5C,sCAAsC;YACtC,+CAA+C;YAC/C,+CAA+C;YAC/C,uDAAuD;YACvD,yDAAyD;YACzD,6FAA6F;SAC9F;KACF;IACD,IAAI,EAAE;QACJ,WAAW,EAAE,qcAAqc;QACld,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE,QAAQ,EAAE,IAAI,EAAE;YAC5H,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kDAAkD,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC3G,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oGAAoG,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC5J,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kKAAkK,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC5N,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,sIAAsI,EAAE,QAAQ,EAAE,KAAK,EAAE;YAC1M,iBAAiB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,8PAA8P,EAAE,QAAQ,EAAE,KAAK,EAAE;SACrU;QACD,OAAO,EAAE,yTAAyT;QAClU,QAAQ,EAAE;YACR,uEAAuE;YACvE,2EAA2E;YAC3E,yEAAyE;YACzE,wFAAwF;YACxF,0FAA0F;YAC1F,wHAAwH;SACzH;QACD,QAAQ,EAAE;YACR,2CAA2C;YAC3C,6EAA6E;YAC7E,mCAAmC;YACnC,6EAA6E;YAC7E,0DAA0D;YAC1D,qDAAqD;SACtD;QACD,WAAW,EAAE,uFAAuF;QACpG,aAAa,EAAE;YACb,iDAAiD;YACjD,qDAAqD;YACrD,2CAA2C;YAC3C,oDAAoD;YACpD,wEAAwE;YACxE,wDAAwD;SACzD;QACD,QAAQ,EAAE;YACR,sEAAsE;YACtE,8EAA8E;YAC9E,4CAA4C;YAC5C,2EAA2E;YAC3E,yEAAyE;SAC1E;QACD,YAAY,EAAE,CAAC,mCAAmC,EAAE,4CAA4C,EAAE,uCAAuC,CAAC;KAC3I;CACF,CAAC"}
|
||||||
2
dist/mcp/tool-docs/index.d.ts.map
vendored
2
dist/mcp/tool-docs/index.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA6B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAoChE,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA8B5C,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAqChE,CAAC;AAGF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
||||||
3
dist/mcp/tool-docs/index.js
vendored
3
dist/mcp/tool-docs/index.js
vendored
@@ -30,6 +30,7 @@ exports.toolsDocumentation = {
|
|||||||
n8n_executions: workflow_management_1.n8nExecutionsDoc,
|
n8n_executions: workflow_management_1.n8nExecutionsDoc,
|
||||||
n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc,
|
n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc,
|
||||||
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc,
|
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc,
|
||||||
n8n_manage_datatable: workflow_management_1.n8nManageDatatableDoc
|
n8n_manage_datatable: workflow_management_1.n8nManageDatatableDoc,
|
||||||
|
n8n_generate_workflow: workflow_management_1.n8nGenerateWorkflowDoc
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=index.js.map
|
//# sourceMappingURL=index.js.map
|
||||||
2
dist/mcp/tool-docs/index.js.map
vendored
2
dist/mcp/tool-docs/index.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":";;;AAGA,2CAA6C;AAC7C,mDAA6C;AAC7C,6CAAoE;AACpE,2CAAiE;AACjE,qCAGkB;AAClB,qCAAyC;AACzC,+DAc+B;AAGlB,QAAA,kBAAkB,GAAsC;IAEnE,mBAAmB,EAAE,8BAAqB;IAC1C,gBAAgB,EAAE,0BAAiB;IAGnC,eAAe,EAAE,sBAAa;IAG9B,YAAY,EAAE,0BAAc;IAG5B,QAAQ,EAAE,0BAAU;IAGpB,aAAa,EAAE,4BAAe;IAC9B,iBAAiB,EAAE,gCAAmB;IAGtC,YAAY,EAAE,0BAAc;IAC5B,gBAAgB,EAAE,8BAAkB;IAGpC,mBAAmB,EAAE,0CAAoB;IACzC,gBAAgB,EAAE,uCAAiB;IACnC,wBAAwB,EAAE,8CAAwB;IAClD,2BAA2B,EAAE,iDAA2B;IACxD,mBAAmB,EAAE,0CAAoB;IACzC,kBAAkB,EAAE,yCAAmB;IACvC,qBAAqB,EAAE,4CAAsB;IAC7C,oBAAoB,EAAE,2CAAqB;IAC3C,iBAAiB,EAAE,wCAAkB;IACrC,cAAc,EAAE,sCAAgB;IAChC,qBAAqB,EAAE,4CAAsB;IAC7C,mBAAmB,EAAE,0CAAoB;IACzC,oBAAoB,EAAE,2CAAqB;CAC5C,CAAC"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/tool-docs/index.ts"],"names":[],"mappings":";;;AAGA,2CAA6C;AAC7C,mDAA6C;AAC7C,6CAAoE;AACpE,2CAAiE;AACjE,qCAGkB;AAClB,qCAAyC;AACzC,+DAe+B;AAGlB,QAAA,kBAAkB,GAAsC;IAEnE,mBAAmB,EAAE,8BAAqB;IAC1C,gBAAgB,EAAE,0BAAiB;IAGnC,eAAe,EAAE,sBAAa;IAG9B,YAAY,EAAE,0BAAc;IAG5B,QAAQ,EAAE,0BAAU;IAGpB,aAAa,EAAE,4BAAe;IAC9B,iBAAiB,EAAE,gCAAmB;IAGtC,YAAY,EAAE,0BAAc;IAC5B,gBAAgB,EAAE,8BAAkB;IAGpC,mBAAmB,EAAE,0CAAoB;IACzC,gBAAgB,EAAE,uCAAiB;IACnC,wBAAwB,EAAE,8CAAwB;IAClD,2BAA2B,EAAE,iDAA2B;IACxD,mBAAmB,EAAE,0CAAoB;IACzC,kBAAkB,EAAE,yCAAmB;IACvC,qBAAqB,EAAE,4CAAsB;IAC7C,oBAAoB,EAAE,2CAAqB;IAC3C,iBAAiB,EAAE,wCAAkB;IACrC,cAAc,EAAE,sCAAgB;IAChC,qBAAqB,EAAE,4CAAsB;IAC7C,mBAAmB,EAAE,0CAAoB;IACzC,oBAAoB,EAAE,2CAAqB;IAC3C,qBAAqB,EAAE,4CAAsB;CAC9C,CAAC"}
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"search-templates.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/templates/search-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,kBAAkB,EAAE,iBA0IhC,CAAC"}
|
{"version":3,"file":"search-templates.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/templates/search-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,kBAAkB,EAAE,iBAoJhC,CAAC"}
|
||||||
46
dist/mcp/tool-docs/templates/search-templates.js
vendored
46
dist/mcp/tool-docs/templates/search-templates.js
vendored
@@ -5,7 +5,7 @@ exports.searchTemplatesDoc = {
|
|||||||
name: 'search_templates',
|
name: 'search_templates',
|
||||||
category: 'templates',
|
category: 'templates',
|
||||||
essentials: {
|
essentials: {
|
||||||
description: 'Unified template search with multiple modes: keyword search, by node types, by task type, or by metadata. 2,700+ templates available.',
|
description: 'Unified template search with multiple modes: keyword search, by node types, by task type, by metadata, or patterns. 2,700+ templates available.',
|
||||||
keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'],
|
keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'],
|
||||||
example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})',
|
example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})',
|
||||||
performance: 'Fast (<100ms) - FTS5 full-text search',
|
performance: 'Fast (<100ms) - FTS5 full-text search',
|
||||||
@@ -13,7 +13,9 @@ exports.searchTemplatesDoc = {
|
|||||||
'searchMode="keyword" (default): Search by name/description',
|
'searchMode="keyword" (default): Search by name/description',
|
||||||
'searchMode="by_nodes": Find templates using specific nodes',
|
'searchMode="by_nodes": Find templates using specific nodes',
|
||||||
'searchMode="by_task": Get curated templates for common tasks',
|
'searchMode="by_task": Get curated templates for common tasks',
|
||||||
'searchMode="by_metadata": Filter by complexity, services, audience'
|
'searchMode="by_metadata": Filter by complexity, services, audience',
|
||||||
|
'searchMode="patterns": Workflow pattern summaries across 10 task categories',
|
||||||
|
'patterns without task: overview of all categories. patterns with task: node frequencies + connection chains'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
full: {
|
full: {
|
||||||
@@ -22,14 +24,15 @@ exports.searchTemplatesDoc = {
|
|||||||
- by_nodes: Find templates that use specific node types
|
- by_nodes: Find templates that use specific node types
|
||||||
- by_task: Get curated templates for predefined task categories
|
- by_task: Get curated templates for predefined task categories
|
||||||
- by_metadata: Filter by complexity, setup time, required services, or target audience
|
- by_metadata: Filter by complexity, setup time, required services, or target audience
|
||||||
|
- patterns: Lightweight workflow pattern summaries mined from 2,700+ templates
|
||||||
|
|
||||||
**Available Task Types (for searchMode="by_task"):**
|
**Available Task Types (for searchMode="by_task" and "patterns"):**
|
||||||
ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`,
|
ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`,
|
||||||
parameters: {
|
parameters: {
|
||||||
searchMode: {
|
searchMode: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: false,
|
required: false,
|
||||||
description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata"'
|
description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata", "patterns"'
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -44,7 +47,7 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
|
|||||||
task: {
|
task: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: false,
|
required: false,
|
||||||
description: 'For searchMode=by_task: Task type (ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations)'
|
description: 'For searchMode=by_task: Task type. For searchMode=patterns: optional category filter (omit for overview of all categories). Values: ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations'
|
||||||
},
|
},
|
||||||
complexity: {
|
complexity: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -92,38 +95,45 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
|
|||||||
description: 'Pagination offset (default 0)'
|
description: 'Pagination offset (default 0)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
returns: `Returns an object containing:
|
returns: `For keyword/by_nodes/by_task/by_metadata modes:
|
||||||
- templates: Array of matching templates
|
- templates: Array of matching templates
|
||||||
- id: Template ID for get_template()
|
- id: Template ID for get_template()
|
||||||
- name: Template name
|
- name, description, author, nodes, views, created, url, metadata
|
||||||
- description: What the workflow does
|
|
||||||
- author: Creator information
|
|
||||||
- nodes: Array of node types used
|
|
||||||
- views: Popularity metric
|
|
||||||
- created: Creation date
|
|
||||||
- url: Link to template
|
|
||||||
- metadata: AI-generated metadata (complexity, services, etc.)
|
|
||||||
- totalFound: Total matching templates
|
- totalFound: Total matching templates
|
||||||
- searchMode: The mode used`,
|
- searchMode: The mode used
|
||||||
|
|
||||||
|
For patterns mode (no task):
|
||||||
|
- templateCount, generatedAt
|
||||||
|
- categories: Array of {category, templateCount, pattern, topNodes}
|
||||||
|
- tip: How to drill into a specific category
|
||||||
|
|
||||||
|
For patterns mode (with task):
|
||||||
|
- category, templateCount, pattern
|
||||||
|
- nodes: Array of {type, freq, role} (top nodes by frequency, limited by 'limit')
|
||||||
|
- chains: Array of {path, count, freq} (top 5 connection chains, short node names)`,
|
||||||
examples: [
|
examples: [
|
||||||
'// Keyword search (default)\nsearch_templates({query: "chatbot"})',
|
'// Keyword search (default)\nsearch_templates({query: "chatbot"})',
|
||||||
'// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})',
|
'// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})',
|
||||||
'// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})',
|
'// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})',
|
||||||
'// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})',
|
'// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})',
|
||||||
'// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})'
|
'// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})',
|
||||||
|
'// Pattern overview — all categories with top nodes (~550 tokens)\nsearch_templates({searchMode: "patterns"})',
|
||||||
|
'// Detailed patterns for a category — node frequencies + connection chains\nsearch_templates({searchMode: "patterns", task: "ai_automation"})'
|
||||||
],
|
],
|
||||||
useCases: [
|
useCases: [
|
||||||
'Find workflows by business purpose (keyword search)',
|
'Find workflows by business purpose (keyword search)',
|
||||||
'Find templates using specific integrations (by_nodes)',
|
'Find templates using specific integrations (by_nodes)',
|
||||||
'Get pre-built solutions for common tasks (by_task)',
|
'Get pre-built solutions for common tasks (by_task)',
|
||||||
'Filter by complexity for team skill level (by_metadata)',
|
'Filter by complexity for team skill level (by_metadata)',
|
||||||
'Find templates requiring specific services (by_metadata)'
|
'Understand common workflow shapes before building (patterns)',
|
||||||
|
'Architecture planning — which nodes go together (patterns)'
|
||||||
],
|
],
|
||||||
performance: `Fast performance across all modes:
|
performance: `Fast performance across all modes:
|
||||||
- keyword: <50ms with FTS5 indexing
|
- keyword: <50ms with FTS5 indexing
|
||||||
- by_nodes: <100ms with indexed lookups
|
- by_nodes: <100ms with indexed lookups
|
||||||
- by_task: <50ms from curated cache
|
- by_task: <50ms from curated cache
|
||||||
- by_metadata: <100ms with filtered queries`,
|
- by_metadata: <100ms with filtered queries
|
||||||
|
- patterns: <10ms (pre-mined, cached in memory)`,
|
||||||
bestPractices: [
|
bestPractices: [
|
||||||
'Use searchMode="by_task" for common automation patterns',
|
'Use searchMode="by_task" for common automation patterns',
|
||||||
'Use searchMode="by_nodes" when you know which integrations you need',
|
'Use searchMode="by_nodes" when you know which integrations you need',
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"search-templates.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/templates/search-templates.ts"],"names":[],"mappings":";;;AAEa,QAAA,kBAAkB,GAAsB;IACnD,IAAI,EAAE,kBAAkB;IACxB,QAAQ,EAAE,WAAW;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,uIAAuI;QACpJ,aAAa,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC;QACpE,OAAO,EAAE,uEAAuE;QAChF,WAAW,EAAE,uCAAuC;QACpD,IAAI,EAAE;YACJ,4DAA4D;YAC5D,4DAA4D;YAC5D,8DAA8D;YAC9D,oEAAoE;SACrE;KACF;IACD,IAAI,EAAE;QACJ,WAAW,EAAE;;;;;;;0KAOyJ;QACtK,UAAU,EAAE;YACV,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,wEAAwE;aACtF;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,yEAAyE;aACvF;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,6GAA6G;aAC3H;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,+MAA+M;aAC7N;YACD,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,kFAAkF;aAChG;YACD,eAAe,EAAE;gBACf,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,mEAAmE;aACjF;YACD,eAAe,EAAE;gBACf,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,mEAAmE;aACjF;YACD,eAAe,EAAE;gBACf,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,4FAA4F;aAC1G;YACD,cAAc,EAAE;gBACd,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,yFAAyF;aACvG;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,oFAAoF;aAClG;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,iHAAiH;aAC/H;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,uCAAuC;aACrD;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,+BAA+B;aAC7C;SACF;QACD,OAAO,EAAE;;;;;;;;;;;;4BAYe;QACxB,QAAQ,EAAE;YACR,mEAAmE;YACnE,uJAAuJ;YACvJ,yGAAyG;YACzG,uHAAuH;YACvH,+HAA+H;SAChI;QACD,QAAQ,EAAE;YACR,qDAAqD;YACrD,uDAAuD;YACvD,oDAAoD;YACpD,yDAAyD;YACzD,0DAA0D;SAC3D;QACD,WAAW,EAAE;;;;4CAI2B;QACxC,aAAa,EAAE;YACb,yDAAyD;YACzD,qEAAqE;YACrE,gDAAgD;YAChD,kDAAkD;YAClD,oDAAoD;SACrD;QACD,QAAQ,EAAE;YACR,kEAAkE;YAClE,mEAAmE;YACnE,8CAA8C;YAC9C,0CAA0C;SAC3C;QACD,YAAY,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,mBAAmB,CAAC;KACpE;CACF,CAAC"}
|
{"version":3,"file":"search-templates.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/templates/search-templates.ts"],"names":[],"mappings":"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"}
|
||||||
@@ -11,4 +11,5 @@ export { n8nExecutionsDoc } from './n8n-executions';
|
|||||||
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
|
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
|
||||||
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
|
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
|
||||||
export { n8nManageDatatableDoc } from './n8n-manage-datatable';
|
export { n8nManageDatatableDoc } from './n8n-manage-datatable';
|
||||||
|
export { n8nGenerateWorkflowDoc } from './n8n-generate-workflow';
|
||||||
//# sourceMappingURL=index.d.ts.map
|
//# sourceMappingURL=index.d.ts.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC"}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.n8nManageDatatableDoc = exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0;
|
exports.n8nGenerateWorkflowDoc = exports.n8nManageDatatableDoc = exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0;
|
||||||
var n8n_create_workflow_1 = require("./n8n-create-workflow");
|
var n8n_create_workflow_1 = require("./n8n-create-workflow");
|
||||||
Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } });
|
Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } });
|
||||||
var n8n_get_workflow_1 = require("./n8n-get-workflow");
|
var n8n_get_workflow_1 = require("./n8n-get-workflow");
|
||||||
@@ -27,4 +27,6 @@ var n8n_deploy_template_1 = require("./n8n-deploy-template");
|
|||||||
Object.defineProperty(exports, "n8nDeployTemplateDoc", { enumerable: true, get: function () { return n8n_deploy_template_1.n8nDeployTemplateDoc; } });
|
Object.defineProperty(exports, "n8nDeployTemplateDoc", { enumerable: true, get: function () { return n8n_deploy_template_1.n8nDeployTemplateDoc; } });
|
||||||
var n8n_manage_datatable_1 = require("./n8n-manage-datatable");
|
var n8n_manage_datatable_1 = require("./n8n-manage-datatable");
|
||||||
Object.defineProperty(exports, "n8nManageDatatableDoc", { enumerable: true, get: function () { return n8n_manage_datatable_1.n8nManageDatatableDoc; } });
|
Object.defineProperty(exports, "n8nManageDatatableDoc", { enumerable: true, get: function () { return n8n_manage_datatable_1.n8nManageDatatableDoc; } });
|
||||||
|
var n8n_generate_workflow_1 = require("./n8n-generate-workflow");
|
||||||
|
Object.defineProperty(exports, "n8nGenerateWorkflowDoc", { enumerable: true, get: function () { return n8n_generate_workflow_1.n8nGenerateWorkflowDoc; } });
|
||||||
//# sourceMappingURL=index.js.map
|
//# sourceMappingURL=index.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":";;;AAAA,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,uDAAuD;AAA9C,qHAAA,iBAAiB,OAAA;AAC1B,uEAAsE;AAA7D,oIAAA,wBAAwB,OAAA;AACjC,6EAA4E;AAAnE,0IAAA,2BAA2B,OAAA;AACpC,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,2DAA2D;AAAlD,yHAAA,mBAAmB,OAAA;AAC5B,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA;AAC9B,yDAAyD;AAAhD,uHAAA,kBAAkB,OAAA;AAC3B,mDAAoD;AAA3C,kHAAA,gBAAgB,OAAA;AACzB,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/index.ts"],"names":[],"mappings":";;;AAAA,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,uDAAuD;AAA9C,qHAAA,iBAAiB,OAAA;AAC1B,uEAAsE;AAA7D,oIAAA,wBAAwB,OAAA;AACjC,6EAA4E;AAAnE,0IAAA,2BAA2B,OAAA;AACpC,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,2DAA2D;AAAlD,yHAAA,mBAAmB,OAAA;AAC5B,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA;AAC9B,yDAAyD;AAAhD,uHAAA,kBAAkB,OAAA;AAC3B,mDAAoD;AAA3C,kHAAA,gBAAgB,OAAA;AACzB,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA;AAC/B,6DAA6D;AAApD,2HAAA,oBAAoB,OAAA;AAC7B,+DAA+D;AAAtD,6HAAA,qBAAqB,OAAA;AAC9B,iEAAiE;AAAxD,+HAAA,sBAAsB,OAAA"}
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"n8n-update-partial-workflow.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,2BAA2B,EAAE,iBA2azC,CAAC"}
|
{"version":3,"file":"n8n-update-partial-workflow.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,2BAA2B,EAAE,iBA0bzC,CAAC"}
|
||||||
@@ -5,7 +5,7 @@ exports.n8nUpdatePartialWorkflowDoc = {
|
|||||||
name: 'n8n_update_partial_workflow',
|
name: 'n8n_update_partial_workflow',
|
||||||
category: 'workflow_management',
|
category: 'workflow_management',
|
||||||
essentials: {
|
essentials: {
|
||||||
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow, transferWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
|
description: 'Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, patchNodeField, moveNode, enable/disableNode, addConnection, removeConnection, rewireConnection, cleanStaleConnections, replaceConnections, updateSettings, updateName, add/removeTag, activateWorkflow, deactivateWorkflow, transferWorkflow. Supports smart parameters (branch, case) for multi-output nodes. Full support for AI connections (ai_languageModel, ai_tool, ai_memory, ai_embedding, ai_vectorStore, ai_document, ai_textSplitter, ai_outputParser).',
|
||||||
keyParameters: ['id', 'operations', 'continueOnError'],
|
keyParameters: ['id', 'operations', 'continueOnError'],
|
||||||
example: 'n8n_update_partial_workflow({id: "wf_123", operations: [{type: "rewireConnection", source: "IF", from: "Old", to: "New", branch: "true"}]})',
|
example: 'n8n_update_partial_workflow({id: "wf_123", operations: [{type: "rewireConnection", source: "IF", from: "Old", to: "New", branch: "true"}]})',
|
||||||
performance: 'Fast (50-200ms)',
|
performance: 'Fast (50-200ms)',
|
||||||
@@ -28,14 +28,15 @@ exports.n8nUpdatePartialWorkflowDoc = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
full: {
|
full: {
|
||||||
description: `Updates workflows using surgical diff operations instead of full replacement. Supports 17 operation types for precise modifications. Operations are validated and applied atomically by default - all succeed or none are applied.
|
description: `Updates workflows using surgical diff operations instead of full replacement. Supports 18 operation types for precise modifications. Operations are validated and applied atomically by default - all succeed or none are applied.
|
||||||
|
|
||||||
## Available Operations:
|
## Available Operations:
|
||||||
|
|
||||||
### Node Operations (6 types):
|
### Node Operations (7 types):
|
||||||
- **addNode**: Add a new node with name, type, and position (required)
|
- **addNode**: Add a new node with name, type, and position (required)
|
||||||
- **removeNode**: Remove a node by ID or name
|
- **removeNode**: Remove a node by ID or name
|
||||||
- **updateNode**: Update node properties using dot notation (e.g., 'parameters.url')
|
- **updateNode**: Update node properties using dot notation (e.g., 'parameters.url')
|
||||||
|
- **patchNodeField**: Surgically edit string fields using find/replace patches. Strict mode: errors if find string not found, errors if multiple matches (ambiguity) unless replaceAll is set. Supports replaceAll and regex flags.
|
||||||
- **moveNode**: Change node position [x, y]
|
- **moveNode**: Change node position [x, y]
|
||||||
- **enableNode**: Enable a disabled node
|
- **enableNode**: Enable a disabled node
|
||||||
- **disableNode**: Disable an active node
|
- **disableNode**: Disable an active node
|
||||||
@@ -336,6 +337,11 @@ n8n_update_partial_workflow({
|
|||||||
'// Validate before applying\nn8n_update_partial_workflow({id: "bcd", operations: [{type: "removeNode", nodeName: "Old Process"}], validateOnly: true})',
|
'// Validate before applying\nn8n_update_partial_workflow({id: "bcd", operations: [{type: "removeNode", nodeName: "Old Process"}], validateOnly: true})',
|
||||||
'// Surgically edit code using __patch_find_replace (avoids replacing entire code block)\nn8n_update_partial_workflow({id: "pfr1", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "const limit = 10;", "replace": "const limit = 50;"}]}}}]})',
|
'// Surgically edit code using __patch_find_replace (avoids replacing entire code block)\nn8n_update_partial_workflow({id: "pfr1", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "const limit = 10;", "replace": "const limit = 50;"}]}}}]})',
|
||||||
'// Multiple sequential patches on the same property\nn8n_update_partial_workflow({id: "pfr2", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "api.old-domain.com", "replace": "api.new-domain.com"}, {"find": "Authorization: Bearer old_token", "replace": "Authorization: Bearer new_token"}]}}}]})',
|
'// Multiple sequential patches on the same property\nn8n_update_partial_workflow({id: "pfr2", operations: [{type: "updateNode", nodeName: "Code", updates: {"parameters.jsCode": {"__patch_find_replace": [{"find": "api.old-domain.com", "replace": "api.new-domain.com"}, {"find": "Authorization: Bearer old_token", "replace": "Authorization: Bearer new_token"}]}}}]})',
|
||||||
|
'\n// ============ PATCHNODEFIELD EXAMPLES (strict find/replace) ============',
|
||||||
|
'// Surgical code edit with patchNodeField (errors if not found)\nn8n_update_partial_workflow({id: "pnf1", operations: [{type: "patchNodeField", nodeName: "Code", fieldPath: "parameters.jsCode", patches: [{find: "const limit = 10;", replace: "const limit = 50;"}]}]})',
|
||||||
|
'// Replace all occurrences of a string\nn8n_update_partial_workflow({id: "pnf2", operations: [{type: "patchNodeField", nodeName: "Code", fieldPath: "parameters.jsCode", patches: [{find: "api.old.com", replace: "api.new.com", replaceAll: true}]}]})',
|
||||||
|
'// Multiple sequential patches\nn8n_update_partial_workflow({id: "pnf3", operations: [{type: "patchNodeField", nodeName: "Set Email", fieldPath: "parameters.assignments.assignments.6.value", patches: [{find: "© 2025 n8n-mcp", replace: "© 2026 n8n-mcp"}, {find: "<p>Unsubscribe</p>", replace: ""}]}]})',
|
||||||
|
'// Regex-based replacement\nn8n_update_partial_workflow({id: "pnf4", operations: [{type: "patchNodeField", nodeName: "Code", fieldPath: "parameters.jsCode", patches: [{find: "const\\\\s+limit\\\\s*=\\\\s*\\\\d+", replace: "const limit = 100", regex: true}]}]})',
|
||||||
'\n// ============ AI CONNECTION EXAMPLES ============',
|
'\n// ============ AI CONNECTION EXAMPLES ============',
|
||||||
'// Connect language model to AI Agent\nn8n_update_partial_workflow({id: "ai1", operations: [{type: "addConnection", source: "OpenAI Chat Model", target: "AI Agent", sourceOutput: "ai_languageModel"}]})',
|
'// Connect language model to AI Agent\nn8n_update_partial_workflow({id: "ai1", operations: [{type: "addConnection", source: "OpenAI Chat Model", target: "AI Agent", sourceOutput: "ai_languageModel"}]})',
|
||||||
'// Connect tool to AI Agent\nn8n_update_partial_workflow({id: "ai2", operations: [{type: "addConnection", source: "HTTP Request Tool", target: "AI Agent", sourceOutput: "ai_tool"}]})',
|
'// Connect tool to AI Agent\nn8n_update_partial_workflow({id: "ai2", operations: [{type: "addConnection", source: "HTTP Request Tool", target: "AI Agent", sourceOutput: "ai_tool"}]})',
|
||||||
@@ -374,7 +380,10 @@ n8n_update_partial_workflow({
|
|||||||
'Configure Vector Store retrieval systems',
|
'Configure Vector Store retrieval systems',
|
||||||
'Swap language models in existing AI workflows',
|
'Swap language models in existing AI workflows',
|
||||||
'Batch-update AI tool connections',
|
'Batch-update AI tool connections',
|
||||||
'Transfer workflows between team projects (enterprise)'
|
'Transfer workflows between team projects (enterprise)',
|
||||||
|
'Surgical string edits in email templates, code, or JSON bodies (patchNodeField)',
|
||||||
|
'Fix typos or update URLs in large HTML content without re-transmitting the full string',
|
||||||
|
'Bulk find/replace across node field content (replaceAll flag)'
|
||||||
],
|
],
|
||||||
performance: 'Very fast - typically 50-200ms. Much faster than full updates as only changes are processed.',
|
performance: 'Very fast - typically 50-200ms. Much faster than full updates as only changes are processed.',
|
||||||
bestPractices: [
|
bestPractices: [
|
||||||
@@ -397,7 +406,10 @@ n8n_update_partial_workflow({
|
|||||||
'To remove properties, set them to null in the updates object',
|
'To remove properties, set them to null in the updates object',
|
||||||
'When migrating from deprecated properties, remove the old property and add the new one in the same operation',
|
'When migrating from deprecated properties, remove the old property and add the new one in the same operation',
|
||||||
'Use null to resolve mutual exclusivity validation errors between properties',
|
'Use null to resolve mutual exclusivity validation errors between properties',
|
||||||
'Batch multiple property removals in a single updateNode operation for efficiency'
|
'Batch multiple property removals in a single updateNode operation for efficiency',
|
||||||
|
'Prefer patchNodeField over __patch_find_replace for strict error handling — patchNodeField errors on not-found and detects ambiguous matches',
|
||||||
|
'Use replaceAll: true in patchNodeField when you want to replace all occurrences of a string',
|
||||||
|
'Use regex: true in patchNodeField for pattern-based replacements (e.g., whitespace-insensitive matching)'
|
||||||
],
|
],
|
||||||
pitfalls: [
|
pitfalls: [
|
||||||
'**REQUIRES N8N_API_URL and N8N_API_KEY environment variables** - will not work without n8n API access',
|
'**REQUIRES N8N_API_URL and N8N_API_KEY environment variables** - will not work without n8n API access',
|
||||||
@@ -420,6 +432,9 @@ n8n_update_partial_workflow({
|
|||||||
'**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated',
|
'**Corrupted workflows beyond repair**: Workflows in paradoxical states (API returns corrupt, API rejects updates) cannot be fixed via API - must be recreated',
|
||||||
'**__patch_find_replace for code edits**: Instead of replacing entire code blocks, use `{"parameters.jsCode": {"__patch_find_replace": [{"find": "old text", "replace": "new text"}]}}` to surgically edit string properties',
|
'**__patch_find_replace for code edits**: Instead of replacing entire code blocks, use `{"parameters.jsCode": {"__patch_find_replace": [{"find": "old text", "replace": "new text"}]}}` to surgically edit string properties',
|
||||||
'__patch_find_replace replaces the FIRST occurrence of each find string. Patches are applied sequentially — order matters',
|
'__patch_find_replace replaces the FIRST occurrence of each find string. Patches are applied sequentially — order matters',
|
||||||
|
'**patchNodeField is strict**: it ERRORS if the find string is not found (unlike __patch_find_replace which only warns)',
|
||||||
|
'**patchNodeField detects ambiguity**: if find matches multiple times, it ERRORS unless replaceAll: true is set',
|
||||||
|
'When using regex: true in patchNodeField, escape special regex characters (., *, +, etc.) if you want literal matching',
|
||||||
'To remove a property, set it to null in the updates object',
|
'To remove a property, set it to null in the updates object',
|
||||||
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with null',
|
'When properties are mutually exclusive (e.g., continueOnFail and onError), setting only the new property will fail - you must remove the old one with null',
|
||||||
'Removing a required property may cause validation errors - check node documentation first',
|
'Removing a required property may cause validation errors - check node documentation first',
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"n8n-update-partial-workflow.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"n8n-update-partial-workflow.js","sourceRoot":"","sources":["../../../../src/mcp/tool-docs/workflow_management/n8n-update-partial-workflow.ts"],"names":[],"mappings":"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"}
|
||||||
2
dist/mcp/tools-documentation.d.ts.map
vendored
2
dist/mcp/tools-documentation.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"tools-documentation.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-documentation.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,YAAY,GAAG,MAAqB,GAAG,MAAM,CA+D1G;AAED,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,YAAY,GAAG,MAAqB,GAAG,MAAM,CAsHpF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAWjE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAM3C"}
|
{"version":3,"file":"tools-documentation.d.ts","sourceRoot":"","sources":["../../src/mcp/tools-documentation.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,YAAY,GAAG,MAAqB,GAAG,MAAM,CA+D1G;AAED,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,YAAY,GAAG,MAAqB,GAAG,MAAM,CAyHpF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAWjE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAM3C"}
|
||||||
7
dist/mcp/tools-documentation.js
vendored
7
dist/mcp/tools-documentation.js
vendored
@@ -98,7 +98,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_node({nodeType: "nodes-base.slack", config: {...}}) - Full validation with errors/warnings/suggestions
|
||||||
- validate_workflow({workflow: {...}}) - Validate entire workflow
|
- validate_workflow({workflow: {...}}) - Validate entire workflow
|
||||||
|
|
||||||
## Tool Categories (19 Tools Total)
|
## Tool Categories (21 Tools Total)
|
||||||
|
|
||||||
**Discovery Tools** (1 tool)
|
**Discovery Tools** (1 tool)
|
||||||
- search_nodes - Full-text search across all nodes (supports OR, AND, FUZZY modes)
|
- search_nodes - Full-text search across all nodes (supports OR, AND, FUZZY modes)
|
||||||
@@ -121,8 +121,9 @@ When working with Code nodes, always start by calling the relevant guide:
|
|||||||
- searchMode='by_nodes': Find templates using specific nodes
|
- searchMode='by_nodes': Find templates using specific nodes
|
||||||
- searchMode='by_task': Curated task-based templates
|
- searchMode='by_task': Curated task-based templates
|
||||||
- searchMode='by_metadata': Filter by complexity/services
|
- 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_create_workflow - Create new workflows
|
||||||
- n8n_get_workflow - Get workflow with mode='full'/'details'/'structure'/'minimal'
|
- n8n_get_workflow - Get workflow with mode='full'/'details'/'structure'/'minimal'
|
||||||
- n8n_update_full_workflow - Full workflow replacement
|
- n8n_update_full_workflow - Full workflow replacement
|
||||||
@@ -136,6 +137,8 @@ When working with Code nodes, always start by calling the relevant guide:
|
|||||||
- n8n_health_check - Check n8n API connectivity
|
- n8n_health_check - Check n8n API connectivity
|
||||||
- n8n_workflow_versions - Version history and rollback
|
- n8n_workflow_versions - Version history and rollback
|
||||||
- n8n_deploy_template - Deploy templates directly to n8n instance
|
- 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
|
## Performance Characteristics
|
||||||
- Instant (<10ms): search_nodes, get_node (minimal/standard)
|
- Instant (<10ms): search_nodes, get_node (minimal/standard)
|
||||||
|
|||||||
2
dist/mcp/tools-documentation.js.map
vendored
2
dist/mcp/tools-documentation.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"tools-documentation.js","sourceRoot":"","sources":["../../src/mcp/tools-documentation.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"tools-documentation.js","sourceRoot":"","sources":["../../src/mcp/tools-documentation.ts"],"names":[],"mappings":";;AAEA,oDA+DC;AAED,4CAyHC;AAED,0DAWC;AAED,gDAIC;AAED,4CAMC;AAvND,2CAAiD;AAEjD,SAAgB,oBAAoB,CAAC,QAAgB,EAAE,QAA+B,YAAY;IAEhG,IAAI,QAAQ,KAAK,4BAA4B,EAAE,CAAC;QAC9C,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,QAAQ,KAAK,wBAAwB,EAAE,CAAC;QAC1C,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,GAAG,8BAAkB,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,QAAQ,gEAAgE,CAAC;IAC3F,CAAC;IAED,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,OAAO,KAAK,IAAI,CAAC,IAAI;;EAEvB,UAAU,CAAC,WAAW;;eAET,UAAU,CAAC,OAAO;;sBAEX,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;;mBAEtC,UAAU,CAAC,WAAW;;;EAGvC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;4DAES,QAAQ,oBAAoB,CAAC;IACvF,CAAC;IAGD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IACtB,OAAO,KAAK,IAAI,CAAC,IAAI;;EAErB,IAAI,CAAC,WAAW;;;EAGhB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CACtD,OAAO,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CACzF,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGV,IAAI,CAAC,OAAO;;;EAGZ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;EAGvE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG7C,IAAI,CAAC,WAAW;;;EAGhB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGlD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG3C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,SAAgB,gBAAgB,CAAC,QAA+B,YAAY;IAE1E,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClD,MAAM,mBAAmB,GAAG,WAAW,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC;IAE/F,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;gDAGqC,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDA6EV,CAAC;IACxD,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;IACtC,OAAO;;;gDAGuC,mBAAmB;;;;;;;;;;EAUjE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACrB,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAClF,OAAO,OAAO,YAAY;EAC1B,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YACrB,MAAM,IAAI,GAAG,8BAAkB,CAAC,QAAQ,CAAC,CAAC;YAC1C,OAAO,OAAO,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QAC7D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;yDAS0C,CAAC;AAC1D,CAAC;AAED,SAAgB,uBAAuB,CAAC,OAAe;IACrD,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,8BAAkB,CAAC,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,GAAG,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,CAAC;QACvG,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,kBAAkB,CAAC,QAAgB;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,8BAAkB,CAAC;SACtC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,SAAgB,gBAAgB;IAC9B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,CAAC,MAAM,CAAC,8BAAkB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC/C,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC;AAGD,SAAS,0BAA0B,CAAC,QAA+B,YAAY;IAC7E,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0FAgC+E,CAAC;IACzF,CAAC;IAGD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA8KoC,CAAC;AAC9C,CAAC;AAED,SAAS,sBAAsB,CAAC,QAA+B,YAAY;IACzE,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sFAgC2E,CAAC;IACrF,CAAC;IAGD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAoO4C,CAAC;AACtD,CAAC"}
|
||||||
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,EAwoB9C,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"}
|
||||||
42
dist/mcp/tools-n8n-manager.js
vendored
42
dist/mcp/tools-n8n-manager.js
vendored
@@ -141,7 +141,7 @@ exports.n8nManagementTools = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'n8n_update_partial_workflow',
|
name: 'n8n_update_partial_workflow',
|
||||||
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag, activate/deactivateWorkflow, transferWorkflow. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
|
description: `Update workflow incrementally with diff operations. Types: addNode, removeNode, updateNode, patchNodeField, moveNode, enable/disableNode, addConnection, removeConnection, updateSettings, updateName, add/removeTag, activate/deactivateWorkflow, transferWorkflow. See tools_documentation("n8n_update_partial_workflow", "full") for details.`,
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
additionalProperties: true,
|
additionalProperties: true,
|
||||||
@@ -635,5 +635,45 @@ exports.n8nManagementTools = [
|
|||||||
openWorldHint: true,
|
openWorldHint: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'n8n_generate_workflow',
|
||||||
|
description: 'Generate an n8n workflow from a natural language description using AI. ' +
|
||||||
|
'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: {
|
||||||
|
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 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'],
|
||||||
|
},
|
||||||
|
annotations: {
|
||||||
|
title: 'Generate Workflow',
|
||||||
|
readOnlyHint: false,
|
||||||
|
destructiveHint: false,
|
||||||
|
idempotentHint: false,
|
||||||
|
openWorldHint: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
//# sourceMappingURL=tools-n8n-manager.js.map
|
//# sourceMappingURL=tools-n8n-manager.js.map
|
||||||
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
2
dist/mcp/tools.d.ts.map
vendored
2
dist/mcp/tools.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,0BAA0B,EAAE,cAAc,EAwatD,CAAC"}
|
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAQ1C,eAAO,MAAM,0BAA0B,EAAE,cAAc,EA6atD,CAAC"}
|
||||||
13
dist/mcp/tools.js
vendored
13
dist/mcp/tools.js
vendored
@@ -52,6 +52,11 @@ exports.n8nDocumentationToolsFinal = [
|
|||||||
description: 'Include top 2 real-world configuration examples from popular templates (default: false)',
|
description: 'Include top 2 real-world configuration examples from popular templates (default: false)',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
includeOperations: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Include resource/operation tree per node. Adds ~100-300 tokens per result but saves a get_node round-trip.',
|
||||||
|
},
|
||||||
source: {
|
source: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
enum: ['all', 'core', 'community', 'verified'],
|
enum: ['all', 'core', 'community', 'verified'],
|
||||||
@@ -237,14 +242,14 @@ exports.n8nDocumentationToolsFinal = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'search_templates',
|
name: 'search_templates',
|
||||||
description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services.`,
|
description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services, 'patterns' for lightweight workflow pattern summaries mined from 2700+ templates.`,
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
searchMode: {
|
searchMode: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata'],
|
enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata', 'patterns'],
|
||||||
description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services',
|
description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services, patterns=lightweight workflow pattern summaries',
|
||||||
default: 'keyword',
|
default: 'keyword',
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
@@ -278,7 +283,7 @@ exports.n8nDocumentationToolsFinal = [
|
|||||||
'api_integration',
|
'api_integration',
|
||||||
'database_operations'
|
'database_operations'
|
||||||
],
|
],
|
||||||
description: 'For searchMode=by_task: the type of task',
|
description: 'For searchMode=by_task: the type of task. For searchMode=patterns: optional category filter (omit for overview of all categories).',
|
||||||
},
|
},
|
||||||
category: {
|
category: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
|||||||
2
dist/mcp/tools.js.map
vendored
2
dist/mcp/tools.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/parsers/property-extractor.d.ts.map
vendored
2
dist/parsers/property-extractor.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"property-extractor.d.ts","sourceRoot":"","sources":["../../src/parsers/property-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,qBAAa,iBAAiB;IAI5B,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAqC9C,OAAO,CAAC,kBAAkB;IA6B1B,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAiC9C,OAAO,CAAC,gCAAgC;IAmDxC,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IA4BrD,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAqC/C,OAAO,CAAC,mBAAmB;CAgB5B"}
|
{"version":3,"file":"property-extractor.d.ts","sourceRoot":"","sources":["../../src/parsers/property-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD,qBAAa,iBAAiB;IAI5B,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAqC9C,OAAO,CAAC,kBAAkB;IA6B1B,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAiC9C,OAAO,CAAC,gCAAgC;IAwDxC,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IA4BrD,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;IAqC/C,OAAO,CAAC,mBAAmB;CAgB5B"}
|
||||||
10
dist/parsers/property-extractor.js
vendored
10
dist/parsers/property-extractor.js
vendored
@@ -95,13 +95,17 @@ class PropertyExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (description.properties && Array.isArray(description.properties)) {
|
if (description.properties && Array.isArray(description.properties)) {
|
||||||
const operationProp = description.properties.find((p) => p.name === 'operation' || p.name === 'action');
|
const operationProps = description.properties.filter((p) => p.name === 'operation' || p.name === 'action');
|
||||||
if (operationProp?.options) {
|
for (const operationProp of operationProps) {
|
||||||
|
if (!operationProp?.options)
|
||||||
|
continue;
|
||||||
|
const resource = operationProp.displayOptions?.show?.resource?.[0];
|
||||||
operationProp.options.forEach((op) => {
|
operationProp.options.forEach((op) => {
|
||||||
operations.push({
|
operations.push({
|
||||||
operation: op.value,
|
operation: op.value,
|
||||||
name: op.name,
|
name: op.name,
|
||||||
description: op.description
|
description: op.description,
|
||||||
|
...(resource ? { resource } : {})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
2
dist/parsers/property-extractor.js.map
vendored
2
dist/parsers/property-extractor.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/services/expression-validator.d.ts
vendored
2
dist/services/expression-validator.d.ts
vendored
@@ -12,6 +12,7 @@ interface ExpressionContext {
|
|||||||
hasInputData?: boolean;
|
hasInputData?: boolean;
|
||||||
}
|
}
|
||||||
export declare class ExpressionValidator {
|
export declare class ExpressionValidator {
|
||||||
|
private static readonly BARE_EXPRESSION_PATTERNS;
|
||||||
private static readonly EXPRESSION_PATTERN;
|
private static readonly EXPRESSION_PATTERN;
|
||||||
private static readonly VARIABLE_PATTERNS;
|
private static readonly VARIABLE_PATTERNS;
|
||||||
static validateExpression(expression: string, context: ExpressionContext): ExpressionValidationResult;
|
static validateExpression(expression: string, context: ExpressionContext): ExpressionValidationResult;
|
||||||
@@ -21,6 +22,7 @@ export declare class ExpressionValidator {
|
|||||||
private static checkCommonMistakes;
|
private static checkCommonMistakes;
|
||||||
private static checkNodeReferences;
|
private static checkNodeReferences;
|
||||||
static validateNodeExpressions(parameters: any, context: ExpressionContext): ExpressionValidationResult;
|
static validateNodeExpressions(parameters: any, context: ExpressionContext): ExpressionValidationResult;
|
||||||
|
private static checkBareExpression;
|
||||||
private static validateParametersRecursive;
|
private static validateParametersRecursive;
|
||||||
}
|
}
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
2
dist/services/expression-validator.d.ts.map
vendored
2
dist/services/expression-validator.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"expression-validator.d.ts","sourceRoot":"","sources":["../../src/services/expression-validator.ts"],"names":[],"mappings":"AAKA,UAAU,0BAA0B;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,UAAU,iBAAiB;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAcvC;IAKF,MAAM,CAAC,kBAAkB,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,iBAAiB,GACzB,0BAA0B;IA2C7B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IA+BhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAwEvC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkDlC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAgBlC,MAAM,CAAC,uBAAuB,CAC5B,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,iBAAiB,GACzB,0BAA0B;IAmB7B,OAAO,CAAC,MAAM,CAAC,2BAA2B;CAiD3C"}
|
{"version":3,"file":"expression-validator.d.ts","sourceRoot":"","sources":["../../src/services/expression-validator.ts"],"names":[],"mappings":"AAKA,UAAU,0BAA0B;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED,UAAU,iBAAiB;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,mBAAmB;IAE9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAS9C;IAGF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAyB;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAcvC;IAKF,MAAM,CAAC,kBAAkB,CACvB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,iBAAiB,GACzB,0BAA0B;IA2C7B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IA+BhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAwEvC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAkDlC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAgBlC,MAAM,CAAC,uBAAuB,CAC5B,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,iBAAiB,GACzB,0BAA0B;IAoB7B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAyBlC,OAAO,CAAC,MAAM,CAAC,2BAA2B;CAoD3C"}
|
||||||
25
dist/services/expression-validator.js
vendored
25
dist/services/expression-validator.js
vendored
@@ -134,6 +134,20 @@ class ExpressionValidator {
|
|||||||
combinedResult.valid = combinedResult.errors.length === 0;
|
combinedResult.valid = combinedResult.errors.length === 0;
|
||||||
return combinedResult;
|
return combinedResult;
|
||||||
}
|
}
|
||||||
|
static checkBareExpression(value, path, result) {
|
||||||
|
if (value.includes('{{') || value.startsWith('=')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const trimmed = value.trim();
|
||||||
|
for (const { pattern, name } of this.BARE_EXPRESSION_PATTERNS) {
|
||||||
|
if (pattern.test(trimmed)) {
|
||||||
|
result.warnings.push((path ? `${path}: ` : '') +
|
||||||
|
`Possible unwrapped expression: "${trimmed}" looks like an n8n ${name} reference. ` +
|
||||||
|
`Use "={{ ${trimmed} }}" to evaluate it as an expression.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
static validateParametersRecursive(obj, context, result, path = '', visited = new WeakSet()) {
|
static validateParametersRecursive(obj, context, result, path = '', visited = new WeakSet()) {
|
||||||
if (obj && typeof obj === 'object') {
|
if (obj && typeof obj === 'object') {
|
||||||
if (visited.has(obj)) {
|
if (visited.has(obj)) {
|
||||||
@@ -142,6 +156,7 @@ class ExpressionValidator {
|
|||||||
visited.add(obj);
|
visited.add(obj);
|
||||||
}
|
}
|
||||||
if (typeof obj === 'string') {
|
if (typeof obj === 'string') {
|
||||||
|
this.checkBareExpression(obj, path, result);
|
||||||
if (obj.includes('{{')) {
|
if (obj.includes('{{')) {
|
||||||
const validation = this.validateExpression(obj, context);
|
const validation = this.validateExpression(obj, context);
|
||||||
validation.errors.forEach(error => {
|
validation.errors.forEach(error => {
|
||||||
@@ -168,6 +183,16 @@ class ExpressionValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.ExpressionValidator = ExpressionValidator;
|
exports.ExpressionValidator = ExpressionValidator;
|
||||||
|
ExpressionValidator.BARE_EXPRESSION_PATTERNS = [
|
||||||
|
{ pattern: /^\$json[.\[]/, name: '$json' },
|
||||||
|
{ pattern: /^\$node\[/, name: '$node' },
|
||||||
|
{ pattern: /^\$input\./, name: '$input' },
|
||||||
|
{ pattern: /^\$execution\./, name: '$execution' },
|
||||||
|
{ pattern: /^\$workflow\./, name: '$workflow' },
|
||||||
|
{ pattern: /^\$prevNode\./, name: '$prevNode' },
|
||||||
|
{ pattern: /^\$env\./, name: '$env' },
|
||||||
|
{ pattern: /^\$(now|today|itemIndex|runIndex)$/, name: 'built-in variable' },
|
||||||
|
];
|
||||||
ExpressionValidator.EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g;
|
ExpressionValidator.EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g;
|
||||||
ExpressionValidator.VARIABLE_PATTERNS = {
|
ExpressionValidator.VARIABLE_PATTERNS = {
|
||||||
json: /\$json(\.[a-zA-Z_][\w]*|\["[^"]+"\]|\['[^']+'\]|\[\d+\])*/g,
|
json: /\$json(\.[a-zA-Z_][\w]*|\["[^"]+"\]|\['[^']+'\]|\[\d+\])*/g,
|
||||||
|
|||||||
2
dist/services/expression-validator.js.map
vendored
2
dist/services/expression-validator.js.map
vendored
File diff suppressed because one or more lines are too long
5
dist/services/n8n-validation.d.ts
vendored
5
dist/services/n8n-validation.d.ts
vendored
@@ -30,10 +30,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
|
|||||||
maxTries?: number | undefined;
|
maxTries?: number | undefined;
|
||||||
waitBetweenTries?: number | undefined;
|
waitBetweenTries?: number | undefined;
|
||||||
alwaysOutputData?: boolean | undefined;
|
alwaysOutputData?: boolean | undefined;
|
||||||
executeOnce?: boolean | undefined;
|
|
||||||
disabled?: boolean | undefined;
|
disabled?: boolean | undefined;
|
||||||
notes?: string | undefined;
|
notes?: string | undefined;
|
||||||
notesInFlow?: boolean | undefined;
|
notesInFlow?: boolean | undefined;
|
||||||
|
executeOnce?: boolean | undefined;
|
||||||
}, {
|
}, {
|
||||||
type: string;
|
type: string;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -47,10 +47,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
|
|||||||
maxTries?: number | undefined;
|
maxTries?: number | undefined;
|
||||||
waitBetweenTries?: number | undefined;
|
waitBetweenTries?: number | undefined;
|
||||||
alwaysOutputData?: boolean | undefined;
|
alwaysOutputData?: boolean | undefined;
|
||||||
executeOnce?: boolean | undefined;
|
|
||||||
disabled?: boolean | undefined;
|
disabled?: boolean | undefined;
|
||||||
notes?: string | undefined;
|
notes?: string | undefined;
|
||||||
notesInFlow?: boolean | undefined;
|
notesInFlow?: boolean | undefined;
|
||||||
|
executeOnce?: boolean | undefined;
|
||||||
}>;
|
}>;
|
||||||
export declare const workflowConnectionSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
export declare const workflowConnectionSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
||||||
main: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
main: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
||||||
@@ -413,6 +413,7 @@ export declare function cleanWorkflowForCreate(workflow: Partial<Workflow>): Par
|
|||||||
export declare function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow>;
|
export declare function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow>;
|
||||||
export declare function validateWorkflowStructure(workflow: Partial<Workflow>): string[];
|
export declare function validateWorkflowStructure(workflow: Partial<Workflow>): string[];
|
||||||
export declare function hasWebhookTrigger(workflow: Workflow): boolean;
|
export declare function hasWebhookTrigger(workflow: Workflow): boolean;
|
||||||
|
export declare function validateConditionNodeStructure(node: WorkflowNode): string[];
|
||||||
export declare function validateFilterBasedNodeMetadata(node: WorkflowNode): string[];
|
export declare function validateFilterBasedNodeMetadata(node: WorkflowNode): string[];
|
||||||
export declare function validateOperatorStructure(operator: any, path: string): string[];
|
export declare function validateOperatorStructure(operator: any, path: string): string[];
|
||||||
export declare function getWebhookUrl(workflow: Workflow): string | null;
|
export declare function getWebhookUrl(workflow: Workflow): string | null;
|
||||||
|
|||||||
2
dist/services/n8n-validation.d.ts.map
vendored
2
dist/services/n8n-validation.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAmBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAkQ/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CA+F5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}
|
{"version":3,"file":"n8n-validation.d.ts","sourceRoot":"","sources":["../../src/services/n8n-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM9E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB7B,CAAC;AAkBH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAUpC,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWjC,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;CAMnC,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,OAAO,GAAG,kBAAkB,CAEpF;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAElG;AAmBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwBrF;AAiBD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsE5E;AAGD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAkQ/E;AAGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAK7D;AAMD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAyB3E;AA2CD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,CAE5E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0D/E;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAmB/D;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CA6CpD;AAGD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAmBpE"}
|
||||||
116
dist/services/n8n-validation.js
vendored
116
dist/services/n8n-validation.js
vendored
@@ -11,6 +11,7 @@ exports.cleanWorkflowForCreate = cleanWorkflowForCreate;
|
|||||||
exports.cleanWorkflowForUpdate = cleanWorkflowForUpdate;
|
exports.cleanWorkflowForUpdate = cleanWorkflowForUpdate;
|
||||||
exports.validateWorkflowStructure = validateWorkflowStructure;
|
exports.validateWorkflowStructure = validateWorkflowStructure;
|
||||||
exports.hasWebhookTrigger = hasWebhookTrigger;
|
exports.hasWebhookTrigger = hasWebhookTrigger;
|
||||||
|
exports.validateConditionNodeStructure = validateConditionNodeStructure;
|
||||||
exports.validateFilterBasedNodeMetadata = validateFilterBasedNodeMetadata;
|
exports.validateFilterBasedNodeMetadata = validateFilterBasedNodeMetadata;
|
||||||
exports.validateOperatorStructure = validateOperatorStructure;
|
exports.validateOperatorStructure = validateOperatorStructure;
|
||||||
exports.getWebhookUrl = getWebhookUrl;
|
exports.getWebhookUrl = getWebhookUrl;
|
||||||
@@ -229,7 +230,7 @@ function validateWorkflowStructure(workflow) {
|
|||||||
}
|
}
|
||||||
if (workflow.nodes) {
|
if (workflow.nodes) {
|
||||||
workflow.nodes.forEach((node, index) => {
|
workflow.nodes.forEach((node, index) => {
|
||||||
const filterErrors = validateFilterBasedNodeMetadata(node);
|
const filterErrors = validateConditionNodeStructure(node);
|
||||||
if (filterErrors.length > 0) {
|
if (filterErrors.length > 0) {
|
||||||
errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`));
|
errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`));
|
||||||
}
|
}
|
||||||
@@ -332,73 +333,66 @@ function hasWebhookTrigger(workflow) {
|
|||||||
return workflow.nodes.some(node => node.type === 'n8n-nodes-base.webhook' ||
|
return workflow.nodes.some(node => node.type === 'n8n-nodes-base.webhook' ||
|
||||||
node.type === 'n8n-nodes-base.webhookTrigger');
|
node.type === 'n8n-nodes-base.webhookTrigger');
|
||||||
}
|
}
|
||||||
function validateFilterBasedNodeMetadata(node) {
|
function validateConditionNodeStructure(node) {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
const isIFNode = node.type === 'n8n-nodes-base.if' && node.typeVersion >= 2.2;
|
const typeVersion = node.typeVersion || 1;
|
||||||
const isSwitchNode = node.type === 'n8n-nodes-base.switch' && node.typeVersion >= 3.2;
|
if (node.type === 'n8n-nodes-base.if') {
|
||||||
if (!isIFNode && !isSwitchNode) {
|
if (typeVersion >= 2.2) {
|
||||||
return errors;
|
errors.push(...validateFilterOptionsRequired(node.parameters?.conditions, 'conditions'));
|
||||||
}
|
errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
|
||||||
if (isIFNode) {
|
|
||||||
const conditions = node.parameters.conditions;
|
|
||||||
if (!conditions?.options) {
|
|
||||||
errors.push('Missing required "conditions.options". ' +
|
|
||||||
'IF v2.2+ requires: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
|
|
||||||
}
|
}
|
||||||
else {
|
else if (typeVersion >= 2) {
|
||||||
const requiredFields = {
|
errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
|
||||||
version: 2,
|
}
|
||||||
leftValue: '',
|
}
|
||||||
caseSensitive: 'boolean',
|
else if (node.type === 'n8n-nodes-base.switch') {
|
||||||
typeValidation: 'strict'
|
if (typeVersion >= 3.2) {
|
||||||
};
|
const rules = node.parameters?.rules;
|
||||||
for (const [field, expectedValue] of Object.entries(requiredFields)) {
|
if (rules?.rules && Array.isArray(rules.rules)) {
|
||||||
if (!(field in conditions.options)) {
|
rules.rules.forEach((rule, i) => {
|
||||||
errors.push(`Missing required field "conditions.options.${field}". ` +
|
errors.push(...validateFilterOptionsRequired(rule.conditions, `rules.rules[${i}].conditions`));
|
||||||
`Expected value: ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue}`);
|
errors.push(...validateFilterConditionOperators(rule.conditions, `rules.rules[${i}].conditions`));
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (conditions?.conditions && Array.isArray(conditions.conditions)) {
|
|
||||||
conditions.conditions.forEach((condition, i) => {
|
|
||||||
const operatorErrors = validateOperatorStructure(condition.operator, `conditions.conditions[${i}].operator`);
|
|
||||||
errors.push(...operatorErrors);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isSwitchNode) {
|
|
||||||
const rules = node.parameters.rules;
|
|
||||||
if (rules?.rules && Array.isArray(rules.rules)) {
|
|
||||||
rules.rules.forEach((rule, ruleIndex) => {
|
|
||||||
if (!rule.conditions?.options) {
|
|
||||||
errors.push(`Missing required "rules.rules[${ruleIndex}].conditions.options". ` +
|
|
||||||
'Switch v3.2+ requires: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const requiredFields = {
|
|
||||||
version: 2,
|
|
||||||
leftValue: '',
|
|
||||||
caseSensitive: 'boolean',
|
|
||||||
typeValidation: 'strict'
|
|
||||||
};
|
|
||||||
for (const [field, expectedValue] of Object.entries(requiredFields)) {
|
|
||||||
if (!(field in rule.conditions.options)) {
|
|
||||||
errors.push(`Missing required field "rules.rules[${ruleIndex}].conditions.options.${field}". ` +
|
|
||||||
`Expected value: ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rule.conditions?.conditions && Array.isArray(rule.conditions.conditions)) {
|
|
||||||
rule.conditions.conditions.forEach((condition, condIndex) => {
|
|
||||||
const operatorErrors = validateOperatorStructure(condition.operator, `rules.rules[${ruleIndex}].conditions.conditions[${condIndex}].operator`);
|
|
||||||
errors.push(...operatorErrors);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
function validateFilterOptionsRequired(conditions, path) {
|
||||||
|
const errors = [];
|
||||||
|
if (!conditions || typeof conditions !== 'object')
|
||||||
|
return errors;
|
||||||
|
if (!conditions.options) {
|
||||||
|
errors.push(`Missing required "${path}.options". ` +
|
||||||
|
'Filter-based nodes require: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const requiredFields = [
|
||||||
|
['version', '2'],
|
||||||
|
['leftValue', '""'],
|
||||||
|
['caseSensitive', 'true'],
|
||||||
|
['typeValidation', '"strict"'],
|
||||||
|
];
|
||||||
|
for (const [field, display] of requiredFields) {
|
||||||
|
if (!(field in conditions.options)) {
|
||||||
|
errors.push(`Missing required field "${path}.options.${field}". Expected value: ${display}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
function validateFilterConditionOperators(conditions, path) {
|
||||||
|
const errors = [];
|
||||||
|
if (!conditions?.conditions || !Array.isArray(conditions.conditions))
|
||||||
|
return errors;
|
||||||
|
conditions.conditions.forEach((condition, i) => {
|
||||||
|
errors.push(...validateOperatorStructure(condition.operator, `${path}.conditions[${i}].operator`));
|
||||||
|
});
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
function validateFilterBasedNodeMetadata(node) {
|
||||||
|
return validateConditionNodeStructure(node);
|
||||||
|
}
|
||||||
function validateOperatorStructure(operator, path) {
|
function validateOperatorStructure(operator, path) {
|
||||||
const errors = [];
|
const errors = [];
|
||||||
if (!operator || typeof operator !== 'object') {
|
if (!operator || typeof operator !== 'object') {
|
||||||
|
|||||||
2
dist/services/n8n-validation.js.map
vendored
2
dist/services/n8n-validation.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"node-specific-validators.d.ts","sourceRoot":"","sources":["../../src/services/node-specific-validators.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAIjC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAqE1D,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkDvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA2CzC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiDjE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA0BzC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkBvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAwCxC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAwF3D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAyG5D,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAkI7D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAmG5D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6F1D,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAkF/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiGhE,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6D5D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA8DzD,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuDrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAuDjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAyFtC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAuKnC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA2EnC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAoDzD"}
|
{"version":3,"file":"node-specific-validators.d.ts","sourceRoot":"","sources":["../../src/services/node-specific-validators.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,qBAAa,sBAAsB;IAIjC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAqE1D,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkDvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA2CzC,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiDjE,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA0BzC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAkBvC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAsBzC,OAAO,CAAC,MAAM,CAAC,0BAA0B;IA4BzC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAwCxC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAwF3D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAyG5D,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAkI7D,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAmG5D,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6F1D,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAkF/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAiGhE,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA6D5D,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IA8DzD,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAuDrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAuDjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAyFtC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAuKnC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IA2EnC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAwDzD"}
|
||||||
8
dist/services/node-specific-validators.js
vendored
8
dist/services/node-specific-validators.js
vendored
@@ -1317,12 +1317,16 @@ class NodeSpecificValidators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (config.mode === 'manual') {
|
if (config.mode === 'manual') {
|
||||||
const hasFields = config.values && Object.keys(config.values).length > 0;
|
const hasFieldsViaValues = config.values && Object.keys(config.values).length > 0;
|
||||||
|
const hasFieldsViaAssignments = config.assignments?.assignments
|
||||||
|
&& Array.isArray(config.assignments.assignments)
|
||||||
|
&& config.assignments.assignments.length > 0;
|
||||||
|
const hasFields = hasFieldsViaValues || hasFieldsViaAssignments;
|
||||||
if (!hasFields && !config.jsonOutput) {
|
if (!hasFields && !config.jsonOutput) {
|
||||||
warnings.push({
|
warnings.push({
|
||||||
type: 'missing_common',
|
type: 'missing_common',
|
||||||
message: 'Set node has no fields configured - will output empty items',
|
message: 'Set node has no fields configured - will output empty items',
|
||||||
suggestion: 'Add fields in the Values section or use JSON mode'
|
suggestion: 'Add field assignments or use JSON mode'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
2
dist/services/workflow-diff-engine.d.ts
vendored
2
dist/services/workflow-diff-engine.d.ts
vendored
@@ -14,6 +14,7 @@ export declare class WorkflowDiffEngine {
|
|||||||
private validateAddNode;
|
private validateAddNode;
|
||||||
private validateRemoveNode;
|
private validateRemoveNode;
|
||||||
private validateUpdateNode;
|
private validateUpdateNode;
|
||||||
|
private validatePatchNodeField;
|
||||||
private validateMoveNode;
|
private validateMoveNode;
|
||||||
private validateToggleNode;
|
private validateToggleNode;
|
||||||
private validateAddConnection;
|
private validateAddConnection;
|
||||||
@@ -22,6 +23,7 @@ export declare class WorkflowDiffEngine {
|
|||||||
private applyAddNode;
|
private applyAddNode;
|
||||||
private applyRemoveNode;
|
private applyRemoveNode;
|
||||||
private applyUpdateNode;
|
private applyUpdateNode;
|
||||||
|
private applyPatchNodeField;
|
||||||
private applyMoveNode;
|
private applyMoveNode;
|
||||||
private applyEnableNode;
|
private applyEnableNode;
|
||||||
private applyDisableNode;
|
private applyDisableNode;
|
||||||
|
|||||||
2
dist/services/workflow-diff-engine.d.ts.map
vendored
2
dist/services/workflow-diff-engine.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"workflow-diff-engine.d.ts","sourceRoot":"","sources":["../../src/services/workflow-diff-engine.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,mBAAmB,EACnB,kBAAkB,EAuBnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAoC,MAAM,kBAAkB,CAAC;AAY9E,qBAAa,kBAAkB;IAE7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,QAAQ,CAAqC;IAErD,OAAO,CAAC,eAAe,CAAqB;IAE5C,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,YAAY,CAAgB;IAEpC,OAAO,CAAC,mBAAmB,CAAqB;IAK1C,SAAS,CACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC;IAgO9B,OAAO,CAAC,iBAAiB;IA0CzB,OAAO,CAAC,cAAc;IA4DtB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IA6D1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,qBAAqB;IAkD7B,OAAO,CAAC,wBAAwB;IA6ChC,OAAO,CAAC,wBAAwB;IAmDhC,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,eAAe;IA6CvB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,sBAAsB;IA0D9B,OAAO,CAAC,kBAAkB;IAiD1B,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,6BAA6B;IAKrC,OAAO,CAAC,0BAA0B;IA0BlC,OAAO,CAAC,0BAA0B;IA+ElC,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,0BAA0B;IAmElC,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,iBAAiB;CAoB1B"}
|
{"version":3,"file":"workflow-diff-engine.d.ts","sourceRoot":"","sources":["../../src/services/workflow-diff-engine.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,mBAAmB,EACnB,kBAAkB,EAwBnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAoC,MAAM,kBAAkB,CAAC;AA6D9E,qBAAa,kBAAkB;IAE7B,OAAO,CAAC,SAAS,CAAkC;IAEnD,OAAO,CAAC,QAAQ,CAAqC;IAErD,OAAO,CAAC,eAAe,CAAqB;IAE5C,OAAO,CAAC,gBAAgB,CAAqB;IAE7C,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,YAAY,CAAgB;IAEpC,OAAO,CAAC,mBAAmB,CAAqB;IAK1C,SAAS,CACb,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC;IAgO9B,OAAO,CAAC,iBAAiB;IA4CzB,OAAO,CAAC,cAAc;IA+DtB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IA6D1B,OAAO,CAAC,sBAAsB;IAuE9B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,qBAAqB;IAkD7B,OAAO,CAAC,wBAAwB;IA6ChC,OAAO,CAAC,wBAAwB;IAmDhC,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,eAAe;IA6CvB,OAAO,CAAC,mBAAmB;IAgE3B,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,sBAAsB;IA0D9B,OAAO,CAAC,kBAAkB;IAiD1B,OAAO,CAAC,qBAAqB;IAuC7B,OAAO,CAAC,qBAAqB;IA0B7B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,6BAA6B;IAKrC,OAAO,CAAC,0BAA0B;IA0BlC,OAAO,CAAC,0BAA0B;IA+ElC,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,0BAA0B;IAmElC,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,iBAAiB;CAyB1B"}
|
||||||
147
dist/services/workflow-diff-engine.js
vendored
147
dist/services/workflow-diff-engine.js
vendored
@@ -6,6 +6,39 @@ const logger_1 = require("../utils/logger");
|
|||||||
const node_sanitizer_1 = require("./node-sanitizer");
|
const node_sanitizer_1 = require("./node-sanitizer");
|
||||||
const node_type_utils_1 = require("../utils/node-type-utils");
|
const node_type_utils_1 = require("../utils/node-type-utils");
|
||||||
const logger = new logger_1.Logger({ prefix: '[WorkflowDiffEngine]' });
|
const logger = new logger_1.Logger({ prefix: '[WorkflowDiffEngine]' });
|
||||||
|
const PATCH_LIMITS = {
|
||||||
|
MAX_PATCHES: 50,
|
||||||
|
MAX_REGEX_LENGTH: 500,
|
||||||
|
MAX_FIELD_SIZE_REGEX: 512 * 1024,
|
||||||
|
};
|
||||||
|
const DANGEROUS_PATH_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
||||||
|
function isUnsafeRegex(pattern) {
|
||||||
|
const nestedQuantifier = /\([^)]*[+*][^)]*\)[+*{]/;
|
||||||
|
if (nestedQuantifier.test(pattern))
|
||||||
|
return true;
|
||||||
|
const overlappingAlternation = /\([^)]*\|[^)]*\)[+*{]/;
|
||||||
|
if (overlappingAlternation.test(pattern)) {
|
||||||
|
const match = pattern.match(/\(([^)]*)\|([^)]*)\)[+*{]/);
|
||||||
|
if (match) {
|
||||||
|
const [, left, right] = match;
|
||||||
|
const broadClasses = ['.', '\\w', '\\d', '\\s', '\\S', '\\W', '\\D', '[^'];
|
||||||
|
const leftHasBroad = broadClasses.some(c => left.includes(c));
|
||||||
|
const rightHasBroad = broadClasses.some(c => right.includes(c));
|
||||||
|
if (leftHasBroad && rightHasBroad)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function countOccurrences(str, search) {
|
||||||
|
let count = 0;
|
||||||
|
let pos = 0;
|
||||||
|
while ((pos = str.indexOf(search, pos)) !== -1) {
|
||||||
|
count++;
|
||||||
|
pos += search.length;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
class WorkflowDiffEngine {
|
class WorkflowDiffEngine {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.renameMap = new Map();
|
this.renameMap = new Map();
|
||||||
@@ -25,7 +58,7 @@ class WorkflowDiffEngine {
|
|||||||
this.tagsToRemove = [];
|
this.tagsToRemove = [];
|
||||||
this.transferToProjectId = undefined;
|
this.transferToProjectId = undefined;
|
||||||
const workflowCopy = JSON.parse(JSON.stringify(workflow));
|
const workflowCopy = JSON.parse(JSON.stringify(workflow));
|
||||||
const nodeOperationTypes = ['addNode', 'removeNode', 'updateNode', 'moveNode', 'enableNode', 'disableNode'];
|
const nodeOperationTypes = ['addNode', 'removeNode', 'updateNode', 'patchNodeField', 'moveNode', 'enableNode', 'disableNode'];
|
||||||
const nodeOperations = [];
|
const nodeOperations = [];
|
||||||
const otherOperations = [];
|
const otherOperations = [];
|
||||||
request.operations.forEach((operation, index) => {
|
request.operations.forEach((operation, index) => {
|
||||||
@@ -213,6 +246,8 @@ class WorkflowDiffEngine {
|
|||||||
return this.validateRemoveNode(workflow, operation);
|
return this.validateRemoveNode(workflow, operation);
|
||||||
case 'updateNode':
|
case 'updateNode':
|
||||||
return this.validateUpdateNode(workflow, operation);
|
return this.validateUpdateNode(workflow, operation);
|
||||||
|
case 'patchNodeField':
|
||||||
|
return this.validatePatchNodeField(workflow, operation);
|
||||||
case 'moveNode':
|
case 'moveNode':
|
||||||
return this.validateMoveNode(workflow, operation);
|
return this.validateMoveNode(workflow, operation);
|
||||||
case 'enableNode':
|
case 'enableNode':
|
||||||
@@ -254,6 +289,9 @@ class WorkflowDiffEngine {
|
|||||||
case 'updateNode':
|
case 'updateNode':
|
||||||
this.applyUpdateNode(workflow, operation);
|
this.applyUpdateNode(workflow, operation);
|
||||||
break;
|
break;
|
||||||
|
case 'patchNodeField':
|
||||||
|
this.applyPatchNodeField(workflow, operation);
|
||||||
|
break;
|
||||||
case 'moveNode':
|
case 'moveNode':
|
||||||
this.applyMoveNode(workflow, operation);
|
this.applyMoveNode(workflow, operation);
|
||||||
break;
|
break;
|
||||||
@@ -375,6 +413,63 @@ class WorkflowDiffEngine {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
validatePatchNodeField(workflow, operation) {
|
||||||
|
if (!operation.nodeId && !operation.nodeName) {
|
||||||
|
return `patchNodeField requires either "nodeId" or "nodeName"`;
|
||||||
|
}
|
||||||
|
if (!operation.fieldPath || typeof operation.fieldPath !== 'string') {
|
||||||
|
return `patchNodeField requires a "fieldPath" string (e.g., "parameters.jsCode")`;
|
||||||
|
}
|
||||||
|
const pathSegments = operation.fieldPath.split('.');
|
||||||
|
if (pathSegments.some(k => DANGEROUS_PATH_KEYS.has(k))) {
|
||||||
|
return `patchNodeField: fieldPath "${operation.fieldPath}" contains a forbidden key (__proto__, constructor, or prototype)`;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(operation.patches) || operation.patches.length === 0) {
|
||||||
|
return `patchNodeField requires a non-empty "patches" array of {find, replace} objects`;
|
||||||
|
}
|
||||||
|
if (operation.patches.length > PATCH_LIMITS.MAX_PATCHES) {
|
||||||
|
return `patchNodeField: too many patches (${operation.patches.length}). Maximum is ${PATCH_LIMITS.MAX_PATCHES} per operation. Split into multiple operations if needed.`;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < operation.patches.length; i++) {
|
||||||
|
const patch = operation.patches[i];
|
||||||
|
if (!patch || typeof patch.find !== 'string' || typeof patch.replace !== 'string') {
|
||||||
|
return `Invalid patch entry at index ${i}: each entry must have "find" (string) and "replace" (string)`;
|
||||||
|
}
|
||||||
|
if (patch.find.length === 0) {
|
||||||
|
return `Invalid patch entry at index ${i}: "find" must not be empty`;
|
||||||
|
}
|
||||||
|
if (patch.regex) {
|
||||||
|
if (patch.find.length > PATCH_LIMITS.MAX_REGEX_LENGTH) {
|
||||||
|
return `Regex pattern at patch index ${i} is too long (${patch.find.length} chars). Maximum is ${PATCH_LIMITS.MAX_REGEX_LENGTH} characters.`;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new RegExp(patch.find);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return `Invalid regex pattern at patch index ${i}: ${e instanceof Error ? e.message : 'invalid regex'}`;
|
||||||
|
}
|
||||||
|
if (isUnsafeRegex(patch.find)) {
|
||||||
|
return `Potentially unsafe regex pattern at patch index ${i}: nested quantifiers or overlapping alternations can cause excessive backtracking. Simplify the pattern or use literal matching (regex: false).`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
||||||
|
if (!node) {
|
||||||
|
return this.formatNodeNotFoundError(workflow, operation.nodeId || operation.nodeName || '', 'patchNodeField');
|
||||||
|
}
|
||||||
|
const currentValue = this.getNestedProperty(node, operation.fieldPath);
|
||||||
|
if (currentValue === undefined) {
|
||||||
|
return `Cannot apply patchNodeField to "${operation.fieldPath}": property does not exist on node "${node.name}"`;
|
||||||
|
}
|
||||||
|
if (typeof currentValue !== 'string') {
|
||||||
|
return `Cannot apply patchNodeField to "${operation.fieldPath}": current value is ${typeof currentValue}, expected string`;
|
||||||
|
}
|
||||||
|
const hasRegex = operation.patches.some(p => p.regex);
|
||||||
|
if (hasRegex && typeof currentValue === 'string' && currentValue.length > PATCH_LIMITS.MAX_FIELD_SIZE_REGEX) {
|
||||||
|
return `Field "${operation.fieldPath}" is too large for regex operations (${Math.round(currentValue.length / 1024)}KB). Maximum is ${PATCH_LIMITS.MAX_FIELD_SIZE_REGEX / 1024}KB. Use literal matching (regex: false) for large fields.`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
validateMoveNode(workflow, operation) {
|
validateMoveNode(workflow, operation) {
|
||||||
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@@ -586,6 +681,51 @@ class WorkflowDiffEngine {
|
|||||||
const sanitized = (0, node_sanitizer_1.sanitizeNode)(node);
|
const sanitized = (0, node_sanitizer_1.sanitizeNode)(node);
|
||||||
Object.assign(node, sanitized);
|
Object.assign(node, sanitized);
|
||||||
}
|
}
|
||||||
|
applyPatchNodeField(workflow, operation) {
|
||||||
|
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
this.modifiedNodeIds.add(node.id);
|
||||||
|
let current = this.getNestedProperty(node, operation.fieldPath);
|
||||||
|
for (let i = 0; i < operation.patches.length; i++) {
|
||||||
|
const patch = operation.patches[i];
|
||||||
|
if (patch.regex) {
|
||||||
|
const globalRegex = new RegExp(patch.find, 'g');
|
||||||
|
const matches = current.match(globalRegex);
|
||||||
|
if (!matches || matches.length === 0) {
|
||||||
|
throw new Error(`patchNodeField: regex pattern "${patch.find}" not found in "${operation.fieldPath}" (patch index ${i}). ` +
|
||||||
|
`Use n8n_get_workflow to inspect the current value.`);
|
||||||
|
}
|
||||||
|
if (matches.length > 1 && !patch.replaceAll) {
|
||||||
|
throw new Error(`patchNodeField: regex pattern "${patch.find}" matches ${matches.length} times in "${operation.fieldPath}" (patch index ${i}). ` +
|
||||||
|
`Set "replaceAll": true to replace all occurrences, or refine the pattern to match exactly once.`);
|
||||||
|
}
|
||||||
|
const regex = patch.replaceAll ? globalRegex : new RegExp(patch.find);
|
||||||
|
current = current.replace(regex, patch.replace);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const occurrences = countOccurrences(current, patch.find);
|
||||||
|
if (occurrences === 0) {
|
||||||
|
throw new Error(`patchNodeField: "${patch.find.substring(0, 80)}" not found in "${operation.fieldPath}" (patch index ${i}). ` +
|
||||||
|
`Ensure the find string exactly matches the current content (including whitespace and newlines). ` +
|
||||||
|
`Use n8n_get_workflow to inspect the current value.`);
|
||||||
|
}
|
||||||
|
if (occurrences > 1 && !patch.replaceAll) {
|
||||||
|
throw new Error(`patchNodeField: "${patch.find.substring(0, 80)}" found ${occurrences} times in "${operation.fieldPath}" (patch index ${i}). ` +
|
||||||
|
`Set "replaceAll": true to replace all occurrences, or use a more specific find string that matches exactly once.`);
|
||||||
|
}
|
||||||
|
if (patch.replaceAll) {
|
||||||
|
current = current.split(patch.find).join(patch.replace);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current = current.replace(patch.find, patch.replace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setNestedProperty(node, operation.fieldPath, current);
|
||||||
|
const sanitized = (0, node_sanitizer_1.sanitizeNode)(node);
|
||||||
|
Object.assign(node, sanitized);
|
||||||
|
}
|
||||||
applyMoveNode(workflow, operation) {
|
applyMoveNode(workflow, operation) {
|
||||||
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
|
||||||
if (!node)
|
if (!node)
|
||||||
@@ -924,6 +1064,8 @@ class WorkflowDiffEngine {
|
|||||||
const keys = path.split('.');
|
const keys = path.split('.');
|
||||||
let current = obj;
|
let current = obj;
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
|
if (DANGEROUS_PATH_KEYS.has(key))
|
||||||
|
return undefined;
|
||||||
if (current == null || typeof current !== 'object')
|
if (current == null || typeof current !== 'object')
|
||||||
return undefined;
|
return undefined;
|
||||||
current = current[key];
|
current = current[key];
|
||||||
@@ -933,6 +1075,9 @@ class WorkflowDiffEngine {
|
|||||||
setNestedProperty(obj, path, value) {
|
setNestedProperty(obj, path, value) {
|
||||||
const keys = path.split('.');
|
const keys = path.split('.');
|
||||||
let current = obj;
|
let current = obj;
|
||||||
|
if (keys.some(k => DANGEROUS_PATH_KEYS.has(k))) {
|
||||||
|
throw new Error(`Invalid property path: "${path}" contains a forbidden key`);
|
||||||
|
}
|
||||||
for (let i = 0; i < keys.length - 1; i++) {
|
for (let i = 0; i < keys.length - 1; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
|
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
|
||||||
|
|||||||
2
dist/services/workflow-diff-engine.js.map
vendored
2
dist/services/workflow-diff-engine.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/services/workflow-validator.d.ts.map
vendored
2
dist/services/workflow-validator.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"workflow-validator.d.ts","sourceRoot":"","sources":["../../src/services/workflow-validator.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"workflow-validator.d.ts","sourceRoot":"","sources":["../../src/services/workflow-validator.ts"],"names":[],"mappings":"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"}
|
||||||
12
dist/services/workflow-validator.js
vendored
12
dist/services/workflow-validator.js
vendored
@@ -14,6 +14,7 @@ const ai_node_validator_1 = require("./ai-node-validator");
|
|||||||
const ai_tool_validators_1 = require("./ai-tool-validators");
|
const ai_tool_validators_1 = require("./ai-tool-validators");
|
||||||
const node_type_utils_1 = require("../utils/node-type-utils");
|
const node_type_utils_1 = require("../utils/node-type-utils");
|
||||||
const node_classification_1 = require("../utils/node-classification");
|
const node_classification_1 = require("../utils/node-classification");
|
||||||
|
const n8n_validation_1 = require("./n8n-validation");
|
||||||
const tool_variant_generator_1 = require("./tool-variant-generator");
|
const tool_variant_generator_1 = require("./tool-variant-generator");
|
||||||
const logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' });
|
const logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' });
|
||||||
exports.VALID_CONNECTION_TYPES = new Set([
|
exports.VALID_CONNECTION_TYPES = new Set([
|
||||||
@@ -367,6 +368,17 @@ class WorkflowValidator {
|
|||||||
message: typeof warning === 'string' ? warning : warning.message || String(warning)
|
message: typeof warning === 'string' ? warning : warning.message || String(warning)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (node.type === 'n8n-nodes-base.if' || node.type === 'n8n-nodes-base.switch') {
|
||||||
|
const conditionErrors = (0, n8n_validation_1.validateConditionNodeStructure)(node);
|
||||||
|
for (const err of conditionErrors) {
|
||||||
|
result.errors.push({
|
||||||
|
type: 'error',
|
||||||
|
nodeId: node.id,
|
||||||
|
nodeName: node.name,
|
||||||
|
message: err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
result.errors.push({
|
result.errors.push({
|
||||||
|
|||||||
2
dist/services/workflow-validator.js.map
vendored
2
dist/services/workflow-validator.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/types/index.d.ts
vendored
1
dist/types/index.d.ts
vendored
@@ -2,6 +2,7 @@ export * from './node-types';
|
|||||||
export * from './type-structures';
|
export * from './type-structures';
|
||||||
export * from './instance-context';
|
export * from './instance-context';
|
||||||
export * from './session-state';
|
export * from './session-state';
|
||||||
|
export * from './generate-workflow';
|
||||||
export interface MCPServerConfig {
|
export interface MCPServerConfig {
|
||||||
port: number;
|
port: number;
|
||||||
host: string;
|
host: string;
|
||||||
|
|||||||
2
dist/types/index.d.ts.map
vendored
2
dist/types/index.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAEhC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,eAAe;IAE9B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IAEF,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE;QACN,EAAE,CAAC,EAAE;YACH,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ"}
|
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,eAAe;IAE9B,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IACF,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACtD,CAAC;IAEF,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE;QACN,EAAE,CAAC,EAAE;YACH,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;CACJ"}
|
||||||
1
dist/types/index.js
vendored
1
dist/types/index.js
vendored
@@ -18,4 +18,5 @@ __exportStar(require("./node-types"), exports);
|
|||||||
__exportStar(require("./type-structures"), exports);
|
__exportStar(require("./type-structures"), exports);
|
||||||
__exportStar(require("./instance-context"), exports);
|
__exportStar(require("./instance-context"), exports);
|
||||||
__exportStar(require("./session-state"), exports);
|
__exportStar(require("./session-state"), exports);
|
||||||
|
__exportStar(require("./generate-workflow"), exports);
|
||||||
//# sourceMappingURL=index.js.map
|
//# sourceMappingURL=index.js.map
|
||||||
2
dist/types/index.js.map
vendored
2
dist/types/index.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,+CAA6B;AAC7B,oDAAkC;AAClC,qDAAmC;AACnC,kDAAgC"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,+CAA6B;AAC7B,oDAAkC;AAClC,qDAAmC;AACnC,kDAAgC;AAChC,sDAAoC"}
|
||||||
16
dist/types/workflow-diff.d.ts
vendored
16
dist/types/workflow-diff.d.ts
vendored
@@ -40,6 +40,18 @@ export interface DisableNodeOperation extends DiffOperation {
|
|||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
nodeName?: string;
|
nodeName?: string;
|
||||||
}
|
}
|
||||||
|
export interface PatchNodeFieldOperation extends DiffOperation {
|
||||||
|
type: 'patchNodeField';
|
||||||
|
nodeId?: string;
|
||||||
|
nodeName?: string;
|
||||||
|
fieldPath: string;
|
||||||
|
patches: Array<{
|
||||||
|
find: string;
|
||||||
|
replace: string;
|
||||||
|
replaceAll?: boolean;
|
||||||
|
regex?: boolean;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
export interface AddConnectionOperation extends DiffOperation {
|
export interface AddConnectionOperation extends DiffOperation {
|
||||||
type: 'addConnection';
|
type: 'addConnection';
|
||||||
source: string;
|
source: string;
|
||||||
@@ -114,7 +126,7 @@ export interface ReplaceConnectionsOperation extends DiffOperation {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export type WorkflowDiffOperation = AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation | AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation | ActivateWorkflowOperation | DeactivateWorkflowOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation | TransferWorkflowOperation;
|
export type WorkflowDiffOperation = AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | PatchNodeFieldOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation | AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation | ActivateWorkflowOperation | DeactivateWorkflowOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation | TransferWorkflowOperation;
|
||||||
export interface WorkflowDiffRequest {
|
export interface WorkflowDiffRequest {
|
||||||
id: string;
|
id: string;
|
||||||
operations: WorkflowDiffOperation[];
|
operations: WorkflowDiffOperation[];
|
||||||
@@ -149,7 +161,7 @@ export interface NodeReference {
|
|||||||
id?: string;
|
id?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
export declare function isNodeOperation(op: WorkflowDiffOperation): op is AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation;
|
export declare function isNodeOperation(op: WorkflowDiffOperation): op is AddNodeOperation | RemoveNodeOperation | UpdateNodeOperation | PatchNodeFieldOperation | MoveNodeOperation | EnableNodeOperation | DisableNodeOperation;
|
||||||
export declare function isConnectionOperation(op: WorkflowDiffOperation): op is AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation;
|
export declare function isConnectionOperation(op: WorkflowDiffOperation): op is AddConnectionOperation | RemoveConnectionOperation | RewireConnectionOperation | CleanStaleConnectionsOperation | ReplaceConnectionsOperation;
|
||||||
export declare function isMetadataOperation(op: WorkflowDiffOperation): op is UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation;
|
export declare function isMetadataOperation(op: WorkflowDiffOperation): op is UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation;
|
||||||
//# sourceMappingURL=workflow-diff.d.ts.map
|
//# sourceMappingURL=workflow-diff.d.ts.map
|
||||||
2
dist/types/workflow-diff.d.ts.map
vendored
2
dist/types/workflow-diff.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"workflow-diff.d.ts","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"workflow-diff.d.ts","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":"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"}
|
||||||
2
dist/types/workflow-diff.js
vendored
2
dist/types/workflow-diff.js
vendored
@@ -4,7 +4,7 @@ exports.isNodeOperation = isNodeOperation;
|
|||||||
exports.isConnectionOperation = isConnectionOperation;
|
exports.isConnectionOperation = isConnectionOperation;
|
||||||
exports.isMetadataOperation = isMetadataOperation;
|
exports.isMetadataOperation = isMetadataOperation;
|
||||||
function isNodeOperation(op) {
|
function isNodeOperation(op) {
|
||||||
return ['addNode', 'removeNode', 'updateNode', 'moveNode', 'enableNode', 'disableNode'].includes(op.type);
|
return ['addNode', 'removeNode', 'updateNode', 'patchNodeField', 'moveNode', 'enableNode', 'disableNode'].includes(op.type);
|
||||||
}
|
}
|
||||||
function isConnectionOperation(op) {
|
function isConnectionOperation(op) {
|
||||||
return ['addConnection', 'removeConnection', 'rewireConnection', 'cleanStaleConnections', 'replaceConnections'].includes(op.type);
|
return ['addConnection', 'removeConnection', 'rewireConnection', 'cleanStaleConnections', 'replaceConnections'].includes(op.type);
|
||||||
|
|||||||
2
dist/types/workflow-diff.js.map
vendored
2
dist/types/workflow-diff.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"workflow-diff.js","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":";;AAkNA,0CAIC;AAED,sDAGC;AAED,kDAGC;AAdD,SAAgB,eAAe,CAAC,EAAyB;IAGvD,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AAC5G,CAAC;AAED,SAAgB,qBAAqB,CAAC,EAAyB;IAE7D,OAAO,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACpI,CAAC;AAED,SAAgB,mBAAmB,CAAC,EAAyB;IAE3D,OAAO,CAAC,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC"}
|
{"version":3,"file":"workflow-diff.js","sourceRoot":"","sources":["../../src/types/workflow-diff.ts"],"names":[],"mappings":";;AAgOA,0CAIC;AAED,sDAGC;AAED,kDAGC;AAdD,SAAgB,eAAe,CAAC,EAAyB;IAGvD,OAAO,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AAC9H,CAAC;AAED,SAAgB,qBAAqB,CAAC,EAAyB;IAE7D,OAAO,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACpI,CAAC;AAED,SAAgB,mBAAmB,CAAC,EAAyB;IAE3D,OAAO,CAAC,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;AACnF,CAAC"}
|
||||||
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",
|
"name": "n8n-mcp",
|
||||||
"version": "2.42.2",
|
"version": "2.46.1",
|
||||||
"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",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"n8n-mcp": "./dist/mcp/index.js"
|
"n8n-mcp": "./dist/mcp/stdio-wrapper.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.build.json",
|
"build": "tsc -p tsconfig.build.json",
|
||||||
@@ -140,27 +140,27 @@
|
|||||||
"@vitest/coverage-v8": "^3.2.4",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
"@vitest/runner": "^3.2.4",
|
"@vitest/runner": "^3.2.4",
|
||||||
"@vitest/ui": "^3.2.4",
|
"@vitest/ui": "^3.2.4",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.14.0",
|
||||||
"axios-mock-adapter": "^2.1.0",
|
"axios-mock-adapter": "^2.1.0",
|
||||||
"fishery": "^2.3.1",
|
"fishery": "^2.3.1",
|
||||||
"msw": "^2.10.4",
|
"msw": "^2.10.4",
|
||||||
"nodemon": "^3.1.10",
|
"nodemon": "^3.1.14",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vitest": "^3.2.4"
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.28.0",
|
"@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",
|
"@supabase/supabase-js": "^2.57.4",
|
||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"express-rate-limit": "^7.1.5",
|
"express-rate-limit": "^7.1.5",
|
||||||
"form-data": "^4.0.5",
|
"form-data": "^4.0.5",
|
||||||
"lru-cache": "^11.2.1",
|
"lru-cache": "^11.2.1",
|
||||||
"n8n": "^2.13.3",
|
"n8n": "^2.14.2",
|
||||||
"n8n-core": "^2.13.1",
|
"n8n-core": "^2.14.1",
|
||||||
"n8n-workflow": "^2.13.1",
|
"n8n-workflow": "^2.14.1",
|
||||||
"openai": "^4.77.0",
|
"openai": "^4.77.0",
|
||||||
"sql.js": "^1.13.0",
|
"sql.js": "^1.13.0",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp-runtime",
|
"name": "n8n-mcp-runtime",
|
||||||
"version": "2.33.2",
|
"version": "2.46.0",
|
||||||
"description": "n8n MCP Server Runtime Dependencies Only",
|
"description": "n8n MCP Server Runtime Dependencies Only",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ node -e "
|
|||||||
const pkg = require('./package.json');
|
const pkg = require('./package.json');
|
||||||
pkg.name = 'n8n-mcp';
|
pkg.name = 'n8n-mcp';
|
||||||
pkg.description = 'Integration between n8n workflow automation and Model Context Protocol (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.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
|
||||||
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
||||||
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ pkg.exports = {
|
|||||||
import: './dist/index.js'
|
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.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
|
||||||
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
|
||||||
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
} from './utils/protocol-version';
|
} from './utils/protocol-version';
|
||||||
import { InstanceContext, validateInstanceContext } from './types/instance-context';
|
import { InstanceContext, validateInstanceContext } from './types/instance-context';
|
||||||
import { SessionState } from './types/session-state';
|
import { SessionState } from './types/session-state';
|
||||||
|
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||||
import { closeSharedDatabase } from './database/shared-database';
|
import { closeSharedDatabase } from './database/shared-database';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@@ -45,15 +46,6 @@ interface MultiTenantHeaders {
|
|||||||
const MAX_SESSIONS = Math.max(1, parseInt(process.env.N8N_MCP_MAX_SESSIONS || '100', 10));
|
const MAX_SESSIONS = Math.max(1, parseInt(process.env.N8N_MCP_MAX_SESSIONS || '100', 10));
|
||||||
const SESSION_CLEANUP_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
const SESSION_CLEANUP_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||||
|
|
||||||
interface Session {
|
|
||||||
server: N8NDocumentationMCPServer;
|
|
||||||
transport: StreamableHTTPServerTransport | SSEServerTransport;
|
|
||||||
lastAccess: Date;
|
|
||||||
sessionId: string;
|
|
||||||
initialized: boolean;
|
|
||||||
isSSE: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SessionMetrics {
|
interface SessionMetrics {
|
||||||
totalSessions: number;
|
totalSessions: number;
|
||||||
activeSessions: number;
|
activeSessions: number;
|
||||||
@@ -97,14 +89,18 @@ function logSecurityEvent(
|
|||||||
logger.info(`[SECURITY] ${event}`, logEntry);
|
logger.info(`[SECURITY] ${event}`, logEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SingleSessionHTTPServerOptions {
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
|
}
|
||||||
|
|
||||||
export class SingleSessionHTTPServer {
|
export class SingleSessionHTTPServer {
|
||||||
// Map to store transports by session ID (following SDK pattern)
|
// Map to store transports by session ID (following SDK pattern)
|
||||||
private transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
|
// Stores both StreamableHTTP and SSE transports; use instanceof to discriminate
|
||||||
|
private transports: { [sessionId: string]: StreamableHTTPServerTransport | SSEServerTransport } = {};
|
||||||
private servers: { [sessionId: string]: N8NDocumentationMCPServer } = {};
|
private servers: { [sessionId: string]: N8NDocumentationMCPServer } = {};
|
||||||
private sessionMetadata: { [sessionId: string]: { lastAccess: Date; createdAt: Date } } = {};
|
private sessionMetadata: { [sessionId: string]: { lastAccess: Date; createdAt: Date } } = {};
|
||||||
private sessionContexts: { [sessionId: string]: InstanceContext | undefined } = {};
|
private sessionContexts: { [sessionId: string]: InstanceContext | undefined } = {};
|
||||||
private contextSwitchLocks: Map<string, Promise<void>> = new Map();
|
private contextSwitchLocks: Map<string, Promise<void>> = new Map();
|
||||||
private session: Session | null = null; // Keep for SSE compatibility
|
|
||||||
private consoleManager = new ConsoleManager();
|
private consoleManager = new ConsoleManager();
|
||||||
private expressServer: any;
|
private expressServer: any;
|
||||||
// Session timeout — configurable via SESSION_TIMEOUT_MINUTES environment variable
|
// Session timeout — configurable via SESSION_TIMEOUT_MINUTES environment variable
|
||||||
@@ -114,8 +110,10 @@ export class SingleSessionHTTPServer {
|
|||||||
) * 60 * 1000;
|
) * 60 * 1000;
|
||||||
private authToken: string | null = null;
|
private authToken: string | null = null;
|
||||||
private cleanupTimer: NodeJS.Timeout | null = null;
|
private cleanupTimer: NodeJS.Timeout | null = null;
|
||||||
|
private generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
constructor() {
|
|
||||||
|
constructor(options?: SingleSessionHTTPServerOptions) {
|
||||||
|
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||||
// Validate environment on construction
|
// Validate environment on construction
|
||||||
this.validateEnvironment();
|
this.validateEnvironment();
|
||||||
// No longer pre-create session - will be created per initialize request following SDK pattern
|
// No longer pre-create session - will be created per initialize request following SDK pattern
|
||||||
@@ -312,6 +310,49 @@ export class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate a request by validating the Bearer token.
|
||||||
|
* Returns true if authentication succeeds, false if it fails
|
||||||
|
* (and the response has already been sent with a 401 status).
|
||||||
|
*/
|
||||||
|
private authenticateRequest(req: express.Request, res: express.Response): boolean {
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
|
||||||
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
|
const reason = !authHeader ? 'no_auth_header' : 'invalid_auth_format';
|
||||||
|
logger.warn('Authentication failed', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
reason
|
||||||
|
});
|
||||||
|
res.status(401).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32001, message: 'Unauthorized' },
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = authHeader.slice(7).trim();
|
||||||
|
const isValid = this.authToken && AuthManager.timingSafeCompare(token, this.authToken);
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
logger.warn('Authentication failed: Invalid token', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
reason: 'invalid_token'
|
||||||
|
});
|
||||||
|
res.status(401).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32001, message: 'Unauthorized' },
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch session context with locking to prevent race conditions
|
* Switch session context with locking to prevent race conditions
|
||||||
*/
|
*/
|
||||||
@@ -565,8 +606,10 @@ export class SingleSessionHTTPServer {
|
|||||||
sessionIdToUse = sessionId || uuidv4();
|
sessionIdToUse = sessionId || uuidv4();
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = new N8NDocumentationMCPServer(instanceContext);
|
const server = new N8NDocumentationMCPServer(instanceContext, undefined, {
|
||||||
|
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||||
|
});
|
||||||
|
|
||||||
transport = new StreamableHTTPServerTransport({
|
transport = new StreamableHTTPServerTransport({
|
||||||
sessionIdGenerator: () => sessionIdToUse,
|
sessionIdGenerator: () => sessionIdToUse,
|
||||||
onsessioninitialized: (initializedSessionId: string) => {
|
onsessioninitialized: (initializedSessionId: string) => {
|
||||||
@@ -627,7 +670,22 @@ export class SingleSessionHTTPServer {
|
|||||||
|
|
||||||
// For non-initialize requests: reuse existing transport for this session
|
// For non-initialize requests: reuse existing transport for this session
|
||||||
logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
||||||
transport = this.transports[sessionId];
|
|
||||||
|
// Guard: reject SSE transports on the StreamableHTTP path
|
||||||
|
if (this.transports[sessionId] instanceof SSEServerTransport) {
|
||||||
|
logger.warn('handleRequest: SSE session used on StreamableHTTP endpoint', { sessionId });
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Session uses SSE transport. Send messages to POST /messages?sessionId=<id> instead.'
|
||||||
|
},
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transport = this.transports[sessionId] as StreamableHTTPServerTransport;
|
||||||
|
|
||||||
// TOCTOU guard: session may have been removed between the check above and here
|
// TOCTOU guard: session may have been removed between the check above and here
|
||||||
if (!transport) {
|
if (!transport) {
|
||||||
@@ -742,71 +800,47 @@ export class SingleSessionHTTPServer {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the session for SSE - clean up old and create new SSE transport
|
* Create a new SSE session and store it in the shared transports map.
|
||||||
|
* Following SDK pattern: SSE uses /messages endpoint, separate from /mcp.
|
||||||
*/
|
*/
|
||||||
private async resetSessionSSE(res: express.Response): Promise<void> {
|
private async createSSESession(res: express.Response): Promise<void> {
|
||||||
// Clean up old session if exists
|
if (!this.canCreateSession()) {
|
||||||
if (this.session) {
|
logger.warn('SSE session creation rejected: session limit reached', {
|
||||||
const sessionId = this.session.sessionId;
|
currentSessions: this.getActiveSessionCount(),
|
||||||
logger.info('Closing previous session for SSE', { sessionId });
|
maxSessions: MAX_SESSIONS
|
||||||
|
});
|
||||||
// Close server first to free resources (database, cache timer, etc.)
|
throw new Error(`Session limit reached (${MAX_SESSIONS})`);
|
||||||
// This mirrors the cleanup pattern in removeSession() (issue #542)
|
|
||||||
// Handle server close errors separately so transport close still runs
|
|
||||||
if (this.session.server && typeof this.session.server.close === 'function') {
|
|
||||||
try {
|
|
||||||
await this.session.server.close();
|
|
||||||
} catch (serverError) {
|
|
||||||
logger.warn('Error closing server for SSE session', { sessionId, error: serverError });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close transport last - always attempt even if server.close() failed
|
|
||||||
try {
|
|
||||||
await this.session.transport.close();
|
|
||||||
} catch (transportError) {
|
|
||||||
logger.warn('Error closing transport for SSE session', { sessionId, error: transportError });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// Note: SSE sessions do not support multi-tenant context.
|
||||||
// Create new session
|
// The SaaS backend uses StreamableHTTP exclusively.
|
||||||
logger.info('Creating new N8NDocumentationMCPServer for SSE...');
|
const server = new N8NDocumentationMCPServer(undefined, undefined, {
|
||||||
const server = new N8NDocumentationMCPServer();
|
generateWorkflowHandler: this.generateWorkflowHandler,
|
||||||
|
});
|
||||||
// Generate cryptographically secure session ID
|
|
||||||
const sessionId = uuidv4();
|
const transport = new SSEServerTransport('/messages', res);
|
||||||
|
// Use the SDK-assigned session ID — the client receives this via the SSE
|
||||||
logger.info('Creating SSEServerTransport...');
|
// `endpoint` event and sends it back as ?sessionId on POST /messages.
|
||||||
const transport = new SSEServerTransport('/mcp', res);
|
const sessionId = transport.sessionId;
|
||||||
|
|
||||||
logger.info('Connecting server to SSE transport...');
|
this.transports[sessionId] = transport;
|
||||||
await server.connect(transport);
|
this.servers[sessionId] = server;
|
||||||
|
this.sessionMetadata[sessionId] = {
|
||||||
// Note: server.connect() automatically calls transport.start(), so we don't need to call it again
|
lastAccess: new Date(),
|
||||||
|
createdAt: new Date()
|
||||||
this.session = {
|
};
|
||||||
server,
|
|
||||||
transport,
|
// Clean up on SSE disconnect
|
||||||
lastAccess: new Date(),
|
res.on('close', () => {
|
||||||
sessionId,
|
logger.info('SSE connection closed by client', { sessionId });
|
||||||
initialized: false,
|
this.removeSession(sessionId, 'sse_disconnect').catch(err => {
|
||||||
isSSE: true
|
logger.warn('Error cleaning up SSE session on disconnect', { sessionId, error: err });
|
||||||
};
|
});
|
||||||
|
});
|
||||||
logger.info('Created new SSE session successfully', { sessionId: this.session.sessionId });
|
|
||||||
} catch (error) {
|
await server.connect(transport);
|
||||||
logger.error('Failed to create SSE session:', error);
|
|
||||||
throw error;
|
logger.info('SSE session created', { sessionId, transport: 'SSEServerTransport' });
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if current session is expired
|
|
||||||
*/
|
|
||||||
private isExpired(): boolean {
|
|
||||||
if (!this.session) return true;
|
|
||||||
return Date.now() - this.session.lastAccess.getTime() > this.sessionTimeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -902,7 +936,7 @@ export class SingleSessionHTTPServer {
|
|||||||
authentication: {
|
authentication: {
|
||||||
type: 'Bearer Token',
|
type: 'Bearer Token',
|
||||||
header: 'Authorization: Bearer <token>',
|
header: 'Authorization: Bearer <token>',
|
||||||
required_for: ['POST /mcp']
|
required_for: ['POST /mcp', 'GET /sse', 'POST /messages']
|
||||||
},
|
},
|
||||||
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
||||||
});
|
});
|
||||||
@@ -937,7 +971,7 @@ export class SingleSessionHTTPServer {
|
|||||||
},
|
},
|
||||||
activeTransports: activeTransports.length, // Legacy field
|
activeTransports: activeTransports.length, // Legacy field
|
||||||
activeServers: activeServers.length, // Legacy field
|
activeServers: activeServers.length, // Legacy field
|
||||||
legacySessionActive: !!this.session, // For SSE compatibility
|
legacySessionActive: false, // Deprecated: SSE now uses shared transports map
|
||||||
memory: {
|
memory: {
|
||||||
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
||||||
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
|
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
|
||||||
@@ -994,10 +1028,11 @@ export class SingleSessionHTTPServer {
|
|||||||
app.get('/mcp', async (req, res) => {
|
app.get('/mcp', async (req, res) => {
|
||||||
// Handle StreamableHTTP transport requests with new pattern
|
// Handle StreamableHTTP transport requests with new pattern
|
||||||
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
||||||
if (sessionId && this.transports[sessionId]) {
|
const existingTransport = sessionId ? this.transports[sessionId] : undefined;
|
||||||
|
if (existingTransport && existingTransport instanceof StreamableHTTPServerTransport) {
|
||||||
// Let the StreamableHTTPServerTransport handle the GET request
|
// Let the StreamableHTTPServerTransport handle the GET request
|
||||||
try {
|
try {
|
||||||
await this.transports[sessionId].handleRequest(req, res, undefined);
|
await existingTransport.handleRequest(req, res, undefined);
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('StreamableHTTP GET request failed:', error);
|
logger.error('StreamableHTTP GET request failed:', error);
|
||||||
@@ -1005,26 +1040,15 @@ export class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Accept header for text/event-stream (SSE support)
|
// SSE clients should use GET /sse instead (SDK pattern: separate endpoints)
|
||||||
const accept = req.headers.accept;
|
const accept = req.headers.accept;
|
||||||
if (accept && accept.includes('text/event-stream')) {
|
if (accept && accept.includes('text/event-stream')) {
|
||||||
logger.info('SSE stream request received - establishing SSE connection');
|
logger.info('SSE request on /mcp redirected to /sse', { ip: req.ip });
|
||||||
|
res.status(400).json({
|
||||||
try {
|
error: 'SSE transport uses /sse endpoint',
|
||||||
// Create or reset session for SSE
|
message: 'Connect via GET /sse for SSE streaming. POST messages to /messages?sessionId=<id>.',
|
||||||
await this.resetSessionSSE(res);
|
documentation: 'https://github.com/czlonkowski/n8n-mcp'
|
||||||
logger.info('SSE connection established successfully');
|
});
|
||||||
} catch (error) {
|
|
||||||
logger.error('Failed to establish SSE connection:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32603,
|
|
||||||
message: 'Failed to establish SSE connection'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1061,9 +1085,23 @@ export class SingleSessionHTTPServer {
|
|||||||
mcp: {
|
mcp: {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: '/mcp',
|
path: '/mcp',
|
||||||
description: 'Main MCP JSON-RPC endpoint',
|
description: 'Main MCP JSON-RPC endpoint (StreamableHTTP)',
|
||||||
authentication: 'Bearer token required'
|
authentication: 'Bearer token required'
|
||||||
},
|
},
|
||||||
|
sse: {
|
||||||
|
method: 'GET',
|
||||||
|
path: '/sse',
|
||||||
|
description: 'DEPRECATED: SSE stream for legacy clients. Migrate to StreamableHTTP (POST /mcp).',
|
||||||
|
authentication: 'Bearer token required',
|
||||||
|
deprecated: true
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
method: 'POST',
|
||||||
|
path: '/messages',
|
||||||
|
description: 'DEPRECATED: Message delivery for SSE sessions. Migrate to StreamableHTTP (POST /mcp).',
|
||||||
|
authentication: 'Bearer token required',
|
||||||
|
deprecated: true
|
||||||
|
},
|
||||||
health: {
|
health: {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/health',
|
path: '/health',
|
||||||
@@ -1081,6 +1119,110 @@ export class SingleSessionHTTPServer {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SECURITY: Rate limiting for authentication endpoints
|
||||||
|
// Prevents brute force attacks and DoS
|
||||||
|
// See: https://github.com/czlonkowski/n8n-mcp/issues/265 (HIGH-02)
|
||||||
|
const authLimiter = rateLimit({
|
||||||
|
windowMs: parseInt(process.env.AUTH_RATE_LIMIT_WINDOW || '900000'), // 15 minutes
|
||||||
|
max: parseInt(process.env.AUTH_RATE_LIMIT_MAX || '20'), // 20 authentication attempts per IP
|
||||||
|
message: {
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Too many authentication attempts. Please try again later.'
|
||||||
|
},
|
||||||
|
id: null
|
||||||
|
},
|
||||||
|
standardHeaders: true, // Return rate limit info in `RateLimit-*` headers
|
||||||
|
legacyHeaders: false, // Disable `X-RateLimit-*` headers
|
||||||
|
skipSuccessfulRequests: true, // Only count failed auth attempts (#617)
|
||||||
|
handler: (req, res) => {
|
||||||
|
logger.warn('Rate limit exceeded', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent'),
|
||||||
|
event: 'rate_limit'
|
||||||
|
});
|
||||||
|
res.status(429).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: {
|
||||||
|
code: -32000,
|
||||||
|
message: 'Too many authentication attempts'
|
||||||
|
},
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Legacy SSE stream endpoint (protocol version 2024-11-05)
|
||||||
|
// DEPRECATED: SSE transport is deprecated in MCP SDK v1.x and removed in v2.x.
|
||||||
|
// Clients should migrate to StreamableHTTP (POST /mcp). This endpoint will be
|
||||||
|
// removed in a future major release.
|
||||||
|
app.get('/sse', authLimiter, async (req: express.Request, res: express.Response): Promise<void> => {
|
||||||
|
if (!this.authenticateRequest(req, res)) return;
|
||||||
|
|
||||||
|
logger.warn('SSE transport is deprecated and will be removed in a future release. Migrate to StreamableHTTP (POST /mcp).', {
|
||||||
|
ip: req.ip,
|
||||||
|
userAgent: req.get('user-agent')
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.createSSESession(res);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Failed to create SSE session:', error);
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(error instanceof Error && error.message.includes('Session limit')
|
||||||
|
? 429 : 500
|
||||||
|
).json({
|
||||||
|
error: error instanceof Error ? error.message : 'Failed to establish SSE connection'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// SSE message delivery endpoint (receives JSON-RPC messages from SSE clients)
|
||||||
|
app.post('/messages', authLimiter, jsonParser, async (req: express.Request, res: express.Response): Promise<void> => {
|
||||||
|
if (!this.authenticateRequest(req, res)) return;
|
||||||
|
|
||||||
|
// SSE uses ?sessionId query param (not mcp-session-id header)
|
||||||
|
const sessionId = req.query.sessionId as string | undefined;
|
||||||
|
|
||||||
|
if (!sessionId) {
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32602, message: 'Missing sessionId query parameter' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transport = this.transports[sessionId];
|
||||||
|
|
||||||
|
if (!transport || !(transport instanceof SSEServerTransport)) {
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32000, message: 'SSE session not found or expired' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update session access time
|
||||||
|
this.updateSessionAccess(sessionId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await transport.handlePostMessage(req, res, req.body);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('SSE message handling error', { sessionId, error });
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.status(500).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32603, message: 'Internal error processing SSE message' },
|
||||||
|
id: req.body?.id || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Session termination endpoint
|
// Session termination endpoint
|
||||||
app.delete('/mcp', async (req: express.Request, res: express.Response): Promise<void> => {
|
app.delete('/mcp', async (req: express.Request, res: express.Response): Promise<void> => {
|
||||||
const mcpSessionId = req.headers['mcp-session-id'] as string;
|
const mcpSessionId = req.headers['mcp-session-id'] as string;
|
||||||
@@ -1139,40 +1281,6 @@ export class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// SECURITY: Rate limiting for authentication endpoint
|
|
||||||
// Prevents brute force attacks and DoS
|
|
||||||
// See: https://github.com/czlonkowski/n8n-mcp/issues/265 (HIGH-02)
|
|
||||||
const authLimiter = rateLimit({
|
|
||||||
windowMs: parseInt(process.env.AUTH_RATE_LIMIT_WINDOW || '900000'), // 15 minutes
|
|
||||||
max: parseInt(process.env.AUTH_RATE_LIMIT_MAX || '20'), // 20 authentication attempts per IP
|
|
||||||
message: {
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32000,
|
|
||||||
message: 'Too many authentication attempts. Please try again later.'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
},
|
|
||||||
standardHeaders: true, // Return rate limit info in `RateLimit-*` headers
|
|
||||||
legacyHeaders: false, // Disable `X-RateLimit-*` headers
|
|
||||||
handler: (req, res) => {
|
|
||||||
logger.warn('Rate limit exceeded', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
event: 'rate_limit'
|
|
||||||
});
|
|
||||||
res.status(429).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32000,
|
|
||||||
message: 'Too many authentication attempts'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Main MCP endpoint with authentication and rate limiting
|
// Main MCP endpoint with authentication and rate limiting
|
||||||
app.post('/mcp', authLimiter, jsonParser, async (req: express.Request, res: express.Response): Promise<void> => {
|
app.post('/mcp', authLimiter, jsonParser, async (req: express.Request, res: express.Response): Promise<void> => {
|
||||||
// Log comprehensive debug info about the request
|
// Log comprehensive debug info about the request
|
||||||
@@ -1223,76 +1331,10 @@ export class SingleSessionHTTPServer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced authentication check with specific logging
|
if (!this.authenticateRequest(req, res)) return;
|
||||||
const authHeader = req.headers.authorization;
|
|
||||||
|
|
||||||
// Check if Authorization header is missing
|
|
||||||
if (!authHeader) {
|
|
||||||
logger.warn('Authentication failed: Missing Authorization header', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'no_auth_header'
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if Authorization header has Bearer prefix
|
|
||||||
if (!authHeader.startsWith('Bearer ')) {
|
|
||||||
logger.warn('Authentication failed: Invalid Authorization header format (expected Bearer token)', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'invalid_auth_format',
|
|
||||||
headerPrefix: authHeader.substring(0, Math.min(authHeader.length, 10)) + '...' // Log first 10 chars for debugging
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract token and trim whitespace
|
|
||||||
const token = authHeader.slice(7).trim();
|
|
||||||
|
|
||||||
// SECURITY: Use timing-safe comparison to prevent timing attacks
|
|
||||||
// See: https://github.com/czlonkowski/n8n-mcp/issues/265 (CRITICAL-02)
|
|
||||||
const isValidToken = this.authToken &&
|
|
||||||
AuthManager.timingSafeCompare(token, this.authToken);
|
|
||||||
|
|
||||||
if (!isValidToken) {
|
|
||||||
logger.warn('Authentication failed: Invalid token', {
|
|
||||||
ip: req.ip,
|
|
||||||
userAgent: req.get('user-agent'),
|
|
||||||
reason: 'invalid_token'
|
|
||||||
});
|
|
||||||
res.status(401).json({
|
|
||||||
jsonrpc: '2.0',
|
|
||||||
error: {
|
|
||||||
code: -32001,
|
|
||||||
message: 'Unauthorized'
|
|
||||||
},
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle request with single session
|
|
||||||
logger.info('Authentication successful - proceeding to handleRequest', {
|
logger.info('Authentication successful - proceeding to handleRequest', {
|
||||||
hasSession: !!this.session,
|
activeSessions: this.getActiveSessionCount()
|
||||||
sessionType: this.session?.isSSE ? 'SSE' : 'StreamableHTTP',
|
|
||||||
sessionInitialized: this.session?.initialized
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extract instance context from headers if present (for multi-tenant support)
|
// Extract instance context from headers if present (for multi-tenant support)
|
||||||
@@ -1406,6 +1448,7 @@ export class SingleSessionHTTPServer {
|
|||||||
console.log(`Session Limits: ${MAX_SESSIONS} max sessions, ${this.sessionTimeout / 1000 / 60}min timeout`);
|
console.log(`Session Limits: ${MAX_SESSIONS} max sessions, ${this.sessionTimeout / 1000 / 60}min timeout`);
|
||||||
console.log(`Health check: ${endpoints.health}`);
|
console.log(`Health check: ${endpoints.health}`);
|
||||||
console.log(`MCP endpoint: ${endpoints.mcp}`);
|
console.log(`MCP endpoint: ${endpoints.mcp}`);
|
||||||
|
console.log(`SSE endpoint: ${baseUrl}/sse (legacy clients)`);
|
||||||
|
|
||||||
if (isProduction) {
|
if (isProduction) {
|
||||||
console.log('🔒 Running in PRODUCTION mode - enhanced security enabled');
|
console.log('🔒 Running in PRODUCTION mode - enhanced security enabled');
|
||||||
@@ -1472,17 +1515,6 @@ export class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up legacy session (for SSE compatibility)
|
|
||||||
if (this.session) {
|
|
||||||
try {
|
|
||||||
await this.session.transport.close();
|
|
||||||
logger.info('Legacy session closed');
|
|
||||||
} catch (error) {
|
|
||||||
logger.warn('Error closing legacy session:', error);
|
|
||||||
}
|
|
||||||
this.session = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close Express server
|
// Close Express server
|
||||||
if (this.expressServer) {
|
if (this.expressServer) {
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve) => {
|
||||||
@@ -1521,25 +1553,9 @@ export class SingleSessionHTTPServer {
|
|||||||
};
|
};
|
||||||
} {
|
} {
|
||||||
const metrics = this.getSessionMetrics();
|
const metrics = this.getSessionMetrics();
|
||||||
|
|
||||||
// Legacy SSE session info
|
|
||||||
if (!this.session) {
|
|
||||||
return {
|
|
||||||
active: false,
|
|
||||||
sessions: {
|
|
||||||
total: metrics.totalSessions,
|
|
||||||
active: metrics.activeSessions,
|
|
||||||
expired: metrics.expiredSessions,
|
|
||||||
max: MAX_SESSIONS,
|
|
||||||
sessionIds: Object.keys(this.transports)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
active: true,
|
active: metrics.activeSessions > 0,
|
||||||
sessionId: this.session.sessionId,
|
|
||||||
age: Date.now() - this.session.lastAccess.getTime(),
|
|
||||||
sessions: {
|
sessions: {
|
||||||
total: metrics.totalSessions,
|
total: metrics.totalSessions,
|
||||||
active: metrics.activeSessions,
|
active: metrics.activeSessions,
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ export {
|
|||||||
export type {
|
export type {
|
||||||
SessionState
|
SessionState
|
||||||
} from './types/session-state';
|
} from './types/session-state';
|
||||||
|
export type {
|
||||||
|
GenerateWorkflowArgs,
|
||||||
|
GenerateWorkflowResult,
|
||||||
|
GenerateWorkflowProposal,
|
||||||
|
GenerateWorkflowHandler,
|
||||||
|
GenerateWorkflowHelpers
|
||||||
|
} from './types/generate-workflow';
|
||||||
|
|
||||||
// UI module exports
|
// UI module exports
|
||||||
export type { UIAppConfig, UIMetadata } from './mcp/ui/types';
|
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 { logger } from './utils/logger';
|
||||||
import { InstanceContext } from './types/instance-context';
|
import { InstanceContext } from './types/instance-context';
|
||||||
import { SessionState } from './types/session-state';
|
import { SessionState } from './types/session-state';
|
||||||
|
import { GenerateWorkflowHandler } from './types/generate-workflow';
|
||||||
|
|
||||||
export interface EngineHealth {
|
export interface EngineHealth {
|
||||||
status: 'healthy' | 'unhealthy';
|
status: 'healthy' | 'unhealthy';
|
||||||
@@ -26,6 +27,7 @@ export interface EngineHealth {
|
|||||||
export interface EngineOptions {
|
export interface EngineOptions {
|
||||||
sessionTimeout?: number;
|
sessionTimeout?: number;
|
||||||
logLevel?: 'error' | 'warn' | 'info' | 'debug';
|
logLevel?: 'error' | 'warn' | 'info' | 'debug';
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class N8NMCPEngine {
|
export class N8NMCPEngine {
|
||||||
@@ -33,9 +35,11 @@ export class N8NMCPEngine {
|
|||||||
private startTime: Date;
|
private startTime: Date;
|
||||||
|
|
||||||
constructor(options: EngineOptions = {}) {
|
constructor(options: EngineOptions = {}) {
|
||||||
this.server = new SingleSessionHTTPServer();
|
this.server = new SingleSessionHTTPServer({
|
||||||
|
generateWorkflowHandler: options.generateWorkflowHandler,
|
||||||
|
});
|
||||||
this.startTime = new Date();
|
this.startTime = new Date();
|
||||||
|
|
||||||
if (options.logLevel) {
|
if (options.logLevel) {
|
||||||
process.env.LOG_LEVEL = options.logLevel;
|
process.env.LOG_LEVEL = options.logLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -776,6 +776,28 @@ export async function handleUpdateWorkflow(
|
|||||||
const current = await client.getWorkflow(id);
|
const current = await client.getWorkflow(id);
|
||||||
workflowBefore = JSON.parse(JSON.stringify(current));
|
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)
|
// Create backup before modifying workflow (default: true)
|
||||||
if (createBackup !== false) {
|
if (createBackup !== false) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function getValidator(repository: NodeRepository): WorkflowValidator {
|
|||||||
|
|
||||||
// Operation types that identify nodes by nodeId/nodeName
|
// Operation types that identify nodes by nodeId/nodeName
|
||||||
const NODE_TARGETING_OPERATIONS = new Set([
|
const NODE_TARGETING_OPERATIONS = new Set([
|
||||||
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
|
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode', 'patchNodeField'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Zod schema for the diff request
|
// Zod schema for the diff request
|
||||||
@@ -47,6 +47,8 @@ const workflowDiffSchema = z.object({
|
|||||||
nodeId: z.string().optional(),
|
nodeId: z.string().optional(),
|
||||||
nodeName: z.string().optional(),
|
nodeName: z.string().optional(),
|
||||||
updates: z.any().optional(),
|
updates: z.any().optional(),
|
||||||
|
fieldPath: z.string().optional(),
|
||||||
|
patches: z.any().optional(),
|
||||||
position: z.tuple([z.number(), z.number()]).optional(),
|
position: z.tuple([z.number(), z.number()]).optional(),
|
||||||
// Connection operations
|
// Connection operations
|
||||||
source: z.string().optional(),
|
source: z.string().optional(),
|
||||||
@@ -569,6 +571,8 @@ function inferIntentFromOperations(operations: any[]): string {
|
|||||||
return `Remove node ${op.nodeName || op.nodeId || ''}`.trim();
|
return `Remove node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
case 'updateNode':
|
case 'updateNode':
|
||||||
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
|
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
|
case 'patchNodeField':
|
||||||
|
return `Patch field on node ${op.nodeName || op.nodeId || ''}`.trim();
|
||||||
case 'addConnection':
|
case 'addConnection':
|
||||||
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
|
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
|
||||||
case 'removeConnection':
|
case 'removeConnection':
|
||||||
@@ -604,6 +608,10 @@ function inferIntentFromOperations(operations: any[]): string {
|
|||||||
const count = opTypes.filter((t) => t === 'updateNode').length;
|
const count = opTypes.filter((t) => t === 'updateNode').length;
|
||||||
summary.push(`update ${count} node${count > 1 ? 's' : ''}`);
|
summary.push(`update ${count} node${count > 1 ? 's' : ''}`);
|
||||||
}
|
}
|
||||||
|
if (typeSet.has('patchNodeField')) {
|
||||||
|
const count = opTypes.filter((t) => t === 'patchNodeField').length;
|
||||||
|
summary.push(`patch ${count} field${count > 1 ? 's' : ''}`);
|
||||||
|
}
|
||||||
if (typeSet.has('addConnection') || typeSet.has('rewireConnection')) {
|
if (typeSet.has('addConnection') || typeSet.has('rewireConnection')) {
|
||||||
summary.push('modify connections');
|
summary.push('modify connections');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
STANDARD_PROTOCOL_VERSION
|
STANDARD_PROTOCOL_VERSION
|
||||||
} from '../utils/protocol-version';
|
} from '../utils/protocol-version';
|
||||||
import { InstanceContext } from '../types/instance-context';
|
import { InstanceContext } from '../types/instance-context';
|
||||||
|
import { GenerateWorkflowHandler, GenerateWorkflowHelpers } from '../types/generate-workflow';
|
||||||
import { telemetry } from '../telemetry';
|
import { telemetry } from '../telemetry';
|
||||||
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
|
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
|
||||||
import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints';
|
import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints';
|
||||||
@@ -141,6 +142,10 @@ interface VersionComparisonInfo {
|
|||||||
|
|
||||||
type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo;
|
type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo;
|
||||||
|
|
||||||
|
interface MCPServerOptions {
|
||||||
|
generateWorkflowHandler?: GenerateWorkflowHandler;
|
||||||
|
}
|
||||||
|
|
||||||
export class N8NDocumentationMCPServer {
|
export class N8NDocumentationMCPServer {
|
||||||
private server: Server;
|
private server: Server;
|
||||||
private db: DatabaseAdapter | null = null;
|
private db: DatabaseAdapter | null = null;
|
||||||
@@ -157,10 +162,12 @@ export class N8NDocumentationMCPServer {
|
|||||||
private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup
|
private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup
|
||||||
private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release
|
private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release
|
||||||
private isShutdown: boolean = false; // Prevent double-shutdown
|
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.instanceContext = instanceContext;
|
||||||
this.earlyLogger = earlyLogger || null;
|
this.earlyLogger = earlyLogger || null;
|
||||||
|
this.generateWorkflowHandler = options?.generateWorkflowHandler;
|
||||||
// Check for test environment first
|
// Check for test environment first
|
||||||
const envDbPath = process.env.NODE_DB_PATH;
|
const envDbPath = process.env.NODE_DB_PATH;
|
||||||
let dbPath: string | null = null;
|
let dbPath: string | null = null;
|
||||||
@@ -1531,6 +1538,53 @@ 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(args, 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:
|
default:
|
||||||
throw new Error(`Unknown tool: ${name}`);
|
throw new Error(`Unknown tool: ${name}`);
|
||||||
}
|
}
|
||||||
@@ -3909,17 +3963,23 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
|
|||||||
const patterns = this.workflowPatternsCache!;
|
const patterns = this.workflowPatternsCache!;
|
||||||
|
|
||||||
if (category) {
|
if (category) {
|
||||||
// Return specific category pattern data
|
// Return specific category pattern data (trimmed for token efficiency)
|
||||||
const categoryData = patterns.categories[category];
|
const categoryData = patterns.categories[category];
|
||||||
if (!categoryData) {
|
if (!categoryData) {
|
||||||
const available = Object.keys(patterns.categories);
|
const available = Object.keys(patterns.categories);
|
||||||
return { error: `Unknown category "${category}". Available: ${available.join(', ')}` };
|
return { error: `Unknown category "${category}". Available: ${available.join(', ')}` };
|
||||||
}
|
}
|
||||||
|
const MAX_CHAINS = 5;
|
||||||
return {
|
return {
|
||||||
category,
|
category,
|
||||||
...categoryData,
|
templateCount: categoryData.templateCount,
|
||||||
nodes: categoryData.nodes?.slice(0, limit),
|
pattern: categoryData.pattern,
|
||||||
commonChains: categoryData.commonChains?.slice(0, limit),
|
nodes: categoryData.nodes?.slice(0, limit).map(n => ({
|
||||||
|
type: n.type, freq: n.frequency, role: n.role
|
||||||
|
})),
|
||||||
|
chains: categoryData.commonChains?.slice(0, MAX_CHAINS).map(c => ({
|
||||||
|
path: c.chain.map(t => t.split('.').pop() ?? t), count: c.count, freq: c.frequency
|
||||||
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,21 +26,16 @@ export const searchNodesDoc: ToolDocumentation = {
|
|||||||
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
|
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
|
||||||
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
|
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
|
||||||
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false },
|
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false },
|
||||||
includeOperations: { type: 'boolean', description: 'Include resource/operation tree per node. Default: false. Adds ~100-300 tokens per result but saves a get_node round-trip.', required: false }
|
includeOperations: { type: 'boolean', description: 'Include resource/operation tree per node. Default: false. Adds ~100-300 tokens per result but saves a get_node round-trip. Only returned for nodes with resource/operation patterns — trigger nodes and freeform nodes (Code, HTTP Request) omit this field.', required: false }
|
||||||
},
|
},
|
||||||
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
|
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
|
||||||
examples: [
|
examples: [
|
||||||
'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
|
'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
|
||||||
'search_nodes({query: "database"}) - Returns MySQL, Postgres, MongoDB, Redis, etc.',
|
|
||||||
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
|
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
|
||||||
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
|
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
|
||||||
'search_nodes({query: "http api"}) - Finds HTTP Request, GraphQL, REST nodes',
|
|
||||||
'search_nodes({query: "transform data"}) - Finds Set, Code, Function, Item Lists nodes',
|
|
||||||
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
|
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
|
||||||
'search_nodes({query: "pdf", source: "verified"}) - Find verified community PDF nodes',
|
|
||||||
'search_nodes({query: "brightdata"}) - Find BrightData community node',
|
|
||||||
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples',
|
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples',
|
||||||
'search_nodes({query: "slack", includeOperations: true}) - Get Slack with resource/operation tree'
|
'search_nodes({query: "slack", includeOperations: true}) - Get Slack with resource/operation tree (7 resources, 44 ops)'
|
||||||
],
|
],
|
||||||
useCases: [
|
useCases: [
|
||||||
'Finding nodes when you know partial names',
|
'Finding nodes when you know partial names',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user