Compare commits

...

11 Commits

Author SHA1 Message Date
Romuald Członkowski
12d7d5bdb6 fix: resolve SSE reconnection loop with separate /sse + /messages endpoints (v2.46.1) (#699)
Fix SSE clients entering rapid reconnection loops because POST /mcp
never routed messages to SSEServerTransport.handlePostMessage() (#617).

Root cause: SSE sessions were stored in a separate `this.session` property
invisible to the StreamableHTTP POST handler. The POST handler only
checked `this.transports` (StreamableHTTP map), so SSE messages were
never delivered, causing immediate reconnection and rate limiter exhaustion.

Changes:
- Add GET /sse + POST /messages endpoints following the official MCP SDK
  backward-compatible server pattern (separate endpoints per transport)
- Store SSE transports in the shared this.transports map with instanceof
  guards for type discrimination
- Remove legacy this.session singleton, resetSessionSSE(), and isExpired()
- Extract duplicated auth logic into authenticateRequest() method
- Add Bearer token auth and rate limiting to SSE endpoints
- Add skipSuccessfulRequests to authLimiter to prevent 429 storms
- Mark SSE transport as deprecated (removed in MCP SDK v2.x)

The handleRequest() codepath used by the downstream SaaS backend
(N8NMCPEngine.processRequest()) is unchanged. Session persistence
(exportSessionState/restoreSessionState) is unchanged.

Closes #617

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:00:53 +02:00
Romuald Członkowski
2d4115530c feat: add patchNodeField operation for surgical string edits (v2.46.0) (#698)
Add dedicated `patchNodeField` operation to `n8n_update_partial_workflow`
for surgical find/replace edits in node string fields. Strict alternative
to the existing `__patch_find_replace` in updateNode — errors on not-found,
detects ambiguous matches, supports replaceAll and regex flags.

Security hardening:
- Prototype pollution protection in setNestedProperty/getNestedProperty
- ReDoS protection rejecting unsafe regex patterns (nested quantifiers)
- Resource limits: max 50 patches, 500-char regex, 512KB field size

Fixes #696

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:53:44 +02:00
Romuald Członkowski
ca20586eda fix: use stdio-wrapper as bin entry and preserve credentials on workflow update (v2.45.1) (#695)
Switch the npm bin entry from index.js to stdio-wrapper.js to prevent
INFO-level logs from corrupting the JSON-RPC stdio transport. Also update
both publish scripts so the fix persists across releases. Fixes #693.

Preserve node credentials during full workflow updates. AI-generated node
updates typically omit credential references, causing the n8n API to reject
the PUT. The update handler now merges credentials from the current server-side
workflow when user-provided nodes lack them. Fixes #689.

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:40:17 +02:00
Romuald Członkowski
8888c63e7a chore: update n8n to 2.14.2 and bump version to 2.45.0 (#692)
Update n8n dependencies:
- 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

Preserved 584 community nodes and rebuilt FTS5 search index.

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:38:58 +02:00
Romuald Członkowski
4b109b0870 fix: upgrade GitHub Actions and patch dependency vulnerabilities (v2.44.1) (#690) 2026-04-01 21:17:59 +02:00
czlonkowski
b800ff0cd9 feat: add multi-step flow to n8n_generate_workflow tool (v2.44.0)
Enable AI agents to act as quality gates for workflow generation:
proposals → review → deploy. New parameters: deploy_id, confirm_deploy.
New types: GenerateWorkflowProposal, status field on result.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 00:17:27 +02:00
Romuald Członkowski
77c92716a3 Merge pull request #686 from czlonkowski/feat/generate-workflow-tool
feat: add n8n_generate_workflow tool
2026-03-31 12:45:11 +02:00
czlonkowski
198e773bb3 feat: add n8n_generate_workflow tool for hosted workflow generation
Add new MCP tool that enables AI-powered workflow generation from natural
language descriptions. Uses handler delegation pattern — hosting environments
inject a GenerateWorkflowHandler via EngineOptions, self-hosted instances
receive a hosted-only informational response.

Handler flows through N8NMCPEngine → SingleSessionHTTPServer →
N8NDocumentationMCPServer with helpers for createWorkflow, validateWorkflow,
autofixWorkflow, and getWorkflow.

Includes full tool documentation, tests, and corrected tools overview count.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 12:32:31 +02:00
Romuald Członkowski
3417c6701c Merge pull request #685 from czlonkowski/fix/patterns-docs-and-token-trim-683
fix: trim patterns response tokens and complete documentation (v2.42.3)
2026-03-31 08:11:50 +02:00
czlonkowski
5b68d7fa53 fix: trim patterns response tokens and add missing documentation (#683)
- Trim task-specific patterns ~64%: drop displayName, shorten field names
  (frequency→freq), cap chains at 5, use short node type names in chains
- Add patterns mode to tools_documentation essentials, full docs, and
  tools-documentation.ts overview (was completely missing)
- Document includeOperations omission behavior for trigger/freeform nodes
- Add patterns return shape to search_templates returns documentation
- Trim search_nodes examples from 11 to 6

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 00:03:35 +02:00
Romuald Członkowski
54e445bc6a Merge pull request #682 from czlonkowski/fix/include-patterns-in-npm-681
fix: include workflow-patterns.json in npm package (#681)
2026-03-30 22:27:13 +02:00
116 changed files with 3948 additions and 1758 deletions

View File

@@ -1,10 +1,9 @@
---
name: n8n-mcp-tester
description: Use this agent when you need to test n8n-mcp functionality after implementing fixes or new features. This agent should be invoked proactively after code changes to validate that the MCP tools work correctly with real n8n workflows. The agent tests the actual MCP server tools, not just unit tests. Examples:\n\n<example>\nContext: Developer has just fixed a validation bug in the n8n-mcp server\nuser: "I've fixed the validation issue for HTTP Request nodes"\nassistant: "I've completed the fix. Now let me build the project and then test it."\n<builds project>\nassistant: "Project built successfully. Please reload the MCP server in Claude Desktop to apply the changes."\nuser: "Reloaded"\nassistant: "Great! Now let me invoke the n8n-mcp-tester agent to verify the fix works correctly."\n<commentary>\nSince a fix has been implemented and the MCP server reloaded, use the n8n-mcp-tester agent to validate the fix works in real-world usage.\n</commentary>\n</example>\n\n<example>\nContext: Developer has added a new MCP tool for workflow validation\nuser: "I've implemented the new workflow validation tool"\nassistant: "Implementation complete. Let me build and prepare for testing."\n<builds project>\nassistant: "Build successful. Please reload the MCP server to load the new tool."\nuser: "Done"\nassistant: "Perfect! I'll now use the n8n-mcp-tester agent to test the new workflow validation tool."\n<commentary>\nAfter implementing new MCP functionality and reloading the server, invoke n8n-mcp-tester to verify it works correctly.\n</commentary>\n</example>
tools: Glob, Grep, Read, WebFetch, TodoWrite, WebSearch, mcp__supabase__create_branch, mcp__supabase__list_branches, mcp__supabase__delete_branch, mcp__supabase__merge_branch, mcp__supabase__reset_branch, mcp__supabase__rebase_branch, mcp__supabase__list_tables, mcp__supabase__list_extensions, mcp__supabase__list_migrations, mcp__supabase__apply_migration, mcp__supabase__execute_sql, mcp__supabase__get_logs, mcp__supabase__get_advisors, mcp__supabase__get_project_url, mcp__supabase__generate_typescript_types, mcp__supabase__search_docs, mcp__supabase__list_edge_functions, mcp__supabase__deploy_edge_function, mcp__n8n-mcp__tools_documentation, mcp__n8n-mcp__search_nodes, mcp__n8n-mcp__get_template, mcp__n8n-mcp__search_templates, mcp__n8n-mcp__validate_workflow, mcp__n8n-mcp__n8n_create_workflow, mcp__n8n-mcp__n8n_get_workflow, mcp__n8n-mcp__n8n_update_full_workflow, mcp__n8n-mcp__n8n_update_partial_workflow, mcp__n8n-mcp__n8n_delete_workflow, mcp__n8n-mcp__n8n_list_workflows, mcp__n8n-mcp__n8n_validate_workflow, mcp__n8n-mcp__n8n_trigger_webhook_workflow, mcp__n8n-mcp__n8n_health_check, mcp__brightdata-mcp__search_engine, mcp__brightdata-mcp__scrape_as_markdown, mcp__brightdata-mcp__search_engine_batch, mcp__brightdata-mcp__scrape_batch, mcp__supabase__get_publishable_keys, mcp__supabase__get_edge_function, mcp__n8n-mcp__get_node, mcp__n8n-mcp__validate_node, mcp__n8n-mcp__n8n_autofix_workflow, mcp__n8n-mcp__n8n_executions, mcp__n8n-mcp__n8n_workflow_versions, mcp__n8n-mcp__n8n_deploy_template, mcp__ide__getDiagnostics, mcp__ide__executeCode
description: "Use this agent when you need to test n8n-mcp functionality after implementing fixes or new features. This agent should be invoked proactively after code changes to validate that the MCP tools work correctly with real n8n workflows. The agent tests the actual MCP server tools, not just unit tests. Examples:\\n\\n<example>\\nContext: Developer has just fixed a validation bug in the n8n-mcp server\\nuser: \"I've fixed the validation issue for HTTP Request nodes\"\\nassistant: \"I've completed the fix. Now let me build the project and then test it.\"\\n<builds project>\\nassistant: \"Project built successfully. Please reload the MCP server in Claude Desktop to apply the changes.\"\\nuser: \"Reloaded\"\\nassistant: \"Great! Now let me invoke the n8n-mcp-tester agent to verify the fix works correctly.\"\\n<commentary>\\nSince a fix has been implemented and the MCP server reloaded, use the n8n-mcp-tester agent to validate the fix works in real-world usage.\\n</commentary>\\n</example>\\n\\n<example>\\nContext: Developer has added a new MCP tool for workflow validation\\nuser: \"I've implemented the new workflow validation tool\"\\nassistant: \"Implementation complete. Let me build and prepare for testing.\"\\n<builds project>\\nassistant: \"Build successful. Please reload the MCP server to load the new tool.\"\\nuser: \"Done\"\\nassistant: \"Perfect! I'll now use the n8n-mcp-tester agent to test the new workflow validation tool.\"\\n<commentary>\\nAfter implementing new MCP functionality and reloading the server, invoke n8n-mcp-tester to verify it works correctly.\\n</commentary>\\n</example>"
tools: "Glob, Grep, Read, WebFetch, WebSearch, ListMcpResourcesTool, ReadMcpResourceTool, Bash, mcp__context7__query-docs, mcp__context7__resolve-library-id, mcp__n8n-mcp-testing__get_node, mcp__n8n-mcp-testing__get_template, mcp__n8n-mcp-testing__n8n_autofix_workflow, mcp__n8n-mcp-testing__n8n_create_workflow, mcp__n8n-mcp-testing__n8n_delete_workflow, mcp__n8n-mcp-testing__n8n_deploy_template, mcp__n8n-mcp-testing__n8n_executions, mcp__n8n-mcp-testing__n8n_generate_workflow, mcp__n8n-mcp-testing__n8n_get_workflow, mcp__n8n-mcp-testing__n8n_health_check, mcp__n8n-mcp-testing__n8n_list_workflows, mcp__n8n-mcp-testing__n8n_manage_datatable, mcp__n8n-mcp-testing__n8n_test_workflow, mcp__n8n-mcp-testing__n8n_update_full_workflow, mcp__n8n-mcp-testing__n8n_update_partial_workflow, mcp__n8n-mcp-testing__n8n_validate_workflow, mcp__n8n-mcp-testing__n8n_workflow_versions, mcp__n8n-mcp-testing__search_nodes, mcp__n8n-mcp-testing__search_templates, mcp__n8n-mcp-testing__tools_documentation, mcp__n8n-mcp-testing__validate_node, mcp__n8n-mcp-testing__validate_workflow, mcp__plugin_postgres-best-practices_supabase__authenticate, mcp__supabase-telemetry__apply_migration, mcp__supabase-telemetry__create_branch, mcp__supabase-telemetry__delete_branch, mcp__supabase-telemetry__deploy_edge_function, mcp__supabase-telemetry__execute_sql, mcp__supabase-telemetry__generate_typescript_types, mcp__supabase-telemetry__get_advisors, mcp__supabase-telemetry__get_edge_function, mcp__supabase-telemetry__get_logs, mcp__supabase-telemetry__get_project_url, mcp__supabase-telemetry__get_publishable_keys, mcp__supabase-telemetry__list_branches, mcp__supabase-telemetry__list_edge_functions, mcp__supabase-telemetry__list_extensions, mcp__supabase-telemetry__list_migrations, mcp__supabase-telemetry__list_tables, mcp__supabase-telemetry__merge_branch, mcp__supabase-telemetry__rebase_branch, mcp__supabase-telemetry__reset_branch, mcp__supabase-telemetry__search_docs"
model: sonnet
---
You are n8n-mcp-tester, a specialized testing agent for the n8n Model Context Protocol (MCP) server. You validate that MCP tools and functionality work correctly in real-world scenarios after fixes or new features are implemented.
## Your Core Responsibilities

View File

@@ -36,11 +36,11 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -48,7 +48,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -56,7 +56,7 @@ jobs:
type=raw,value=test-amd64
- name: Build and push Docker image (AMD64 only)
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64

View File

@@ -53,7 +53,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Log in to Docker Hub
uses: docker/login-action@v3
@@ -62,11 +62,11 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -74,7 +74,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -85,7 +85,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
@@ -109,7 +109,7 @@ jobs:
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -167,7 +167,7 @@ jobs:
uses: actions/checkout@v4
- name: Create Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
body: |

View File

@@ -78,15 +78,15 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -94,7 +94,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -107,7 +107,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
no-cache: false
@@ -186,15 +186,15 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -202,7 +202,7 @@ jobs:
- name: Extract metadata for Railway
id: meta-railway
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
tags: |
@@ -215,7 +215,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Railway Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile.railway

View File

@@ -389,7 +389,7 @@ jobs:
echo "Version: $(node -e "console.log(require('./package.json').version)")"
- name: Publish to NPM with retry
uses: nick-invision/retry@v2
uses: nick-invision/retry@v4
with:
timeout_minutes: 5
max_attempts: 3
@@ -448,13 +448,13 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -462,7 +462,7 @@ jobs:
- name: Extract metadata for standard image
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@@ -472,7 +472,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push standard Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
platforms: linux/amd64,linux/arm64
@@ -553,7 +553,7 @@ jobs:
- name: Extract metadata for Railway image
id: meta-railway
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
tags: |
@@ -563,7 +563,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Railway Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile.railway

View File

@@ -116,7 +116,7 @@ jobs:
# Upload coverage to Codecov
- name: Upload coverage to Codecov
if: always()
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
@@ -250,7 +250,7 @@ jobs:
path: artifacts
- name: Publish test results
uses: dorny/test-reporter@v1
uses: dorny/test-reporter@v3
if: always()
continue-on-error: true
with:

View File

@@ -129,7 +129,7 @@ jobs:
- name: Create Pull Request
if: steps.branch.outputs.branch_name != ''
uses: peter-evans/create-pull-request@v5
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ steps.branch.outputs.branch_name }}

View File

@@ -7,6 +7,137 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [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
### Fixed

View File

@@ -5,7 +5,7 @@
[![npm version](https://img.shields.io/npm/v/n8n-mcp.svg)](https://www.npmjs.com/package/n8n-mcp)
[![codecov](https://codecov.io/gh/czlonkowski/n8n-mcp/graph/badge.svg?token=YOUR_TOKEN)](https://codecov.io/gh/czlonkowski/n8n-mcp)
[![Tests](https://img.shields.io/badge/tests-3336%20passing-brightgreen.svg)](https://github.com/czlonkowski/n8n-mcp/actions)
[![n8n version](https://img.shields.io/badge/n8n-2.13.3-orange.svg)](https://github.com/n8n-io/n8n)
[![n8n version](https://img.shields.io/badge/n8n-2.14.2-orange.svg)](https://github.com/n8n-io/n8n)
[![Docker](https://img.shields.io/badge/docker-ghcr.io%2Fczlonkowski%2Fn8n--mcp-green.svg)](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)

Binary file not shown.

View File

@@ -2,19 +2,23 @@
import express from 'express';
import { InstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
export interface SingleSessionHTTPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export declare class SingleSessionHTTPServer {
private transports;
private servers;
private sessionMetadata;
private sessionContexts;
private contextSwitchLocks;
private session;
private consoleManager;
private expressServer;
private sessionTimeout;
private authToken;
private cleanupTimer;
constructor();
private generateWorkflowHandler?;
constructor(options?: SingleSessionHTTPServerOptions);
private startSessionCleanup;
private cleanupExpiredSessions;
private removeSession;
@@ -24,14 +28,14 @@ export declare class SingleSessionHTTPServer {
private isJsonRpcNotification;
private sanitizeErrorForClient;
private updateSessionAccess;
private authenticateRequest;
private switchSessionContext;
private performContextSwitch;
private getSessionMetrics;
private loadAuthToken;
private validateEnvironment;
handleRequest(req: express.Request, res: express.Response, instanceContext?: InstanceContext): Promise<void>;
private resetSessionSSE;
private isExpired;
private createSSESession;
private isSessionExpired;
start(): Promise<void>;
shutdown(): Promise<void>;

View File

@@ -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"}

View File

@@ -45,17 +45,17 @@ function logSecurityEvent(event, details) {
logger_1.logger.info(`[SECURITY] ${event}`, logEntry);
}
class SingleSessionHTTPServer {
constructor() {
constructor(options) {
this.transports = {};
this.servers = {};
this.sessionMetadata = {};
this.sessionContexts = {};
this.contextSwitchLocks = new Map();
this.session = null;
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.cleanupTimer = null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
this.validateEnvironment();
this.startSessionCleanup();
}
@@ -169,6 +169,39 @@ class SingleSessionHTTPServer {
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) {
const existingLock = this.contextSwitchLocks.get(sessionId);
if (existingLock) {
@@ -340,7 +373,9 @@ class SingleSessionHTTPServer {
else {
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({
sessionIdGenerator: () => sessionIdToUse,
onsessioninitialized: (initializedSessionId) => {
@@ -389,6 +424,18 @@ class SingleSessionHTTPServer {
return;
}
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];
if (!transport) {
if (this.isJsonRpcNotification(req.body)) {
@@ -483,52 +530,33 @@ class SingleSessionHTTPServer {
}
});
}
async resetSessionSSE(res) {
if (this.session) {
const sessionId = this.session.sessionId;
logger_1.logger.info('Closing previous session for SSE', { sessionId });
if (this.session.server && typeof this.session.server.close === 'function') {
try {
await this.session.server.close();
}
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 });
}
async createSSESession(res) {
if (!this.canCreateSession()) {
logger_1.logger.warn('SSE session creation rejected: session limit reached', {
currentSessions: this.getActiveSessionCount(),
maxSessions: MAX_SESSIONS
});
throw new Error(`Session limit reached (${MAX_SESSIONS})`);
}
try {
logger_1.logger.info('Creating new N8NDocumentationMCPServer for SSE...');
const server = new server_1.N8NDocumentationMCPServer();
const sessionId = (0, uuid_1.v4)();
logger_1.logger.info('Creating SSEServerTransport...');
const transport = new sse_js_1.SSEServerTransport('/mcp', res);
logger_1.logger.info('Connecting server to SSE transport...');
await server.connect(transport);
this.session = {
server,
transport,
lastAccess: new Date(),
sessionId,
initialized: false,
isSSE: true
};
logger_1.logger.info('Created new SSE session successfully', { sessionId: this.session.sessionId });
}
catch (error) {
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;
const server = new server_1.N8NDocumentationMCPServer(undefined, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
const transport = new sse_js_1.SSEServerTransport('/messages', res);
const sessionId = transport.sessionId;
this.transports[sessionId] = transport;
this.servers[sessionId] = server;
this.sessionMetadata[sessionId] = {
lastAccess: new Date(),
createdAt: new Date()
};
res.on('close', () => {
logger_1.logger.info('SSE connection closed by client', { sessionId });
this.removeSession(sessionId, 'sse_disconnect').catch(err => {
logger_1.logger.warn('Error cleaning up SSE session on disconnect', { sessionId, error: err });
});
});
await server.connect(transport);
logger_1.logger.info('SSE session created', { sessionId, transport: 'SSEServerTransport' });
}
isSessionExpired(sessionId) {
const metadata = this.sessionMetadata[sessionId];
@@ -596,7 +624,7 @@ class SingleSessionHTTPServer {
authentication: {
type: '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'
});
@@ -628,7 +656,7 @@ class SingleSessionHTTPServer {
},
activeTransports: activeTransports.length,
activeServers: activeServers.length,
legacySessionActive: !!this.session,
legacySessionActive: false,
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
@@ -668,9 +696,10 @@ class SingleSessionHTTPServer {
});
app.get('/mcp', async (req, res) => {
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 {
await this.transports[sessionId].handleRequest(req, res, undefined);
await existingTransport.handleRequest(req, res, undefined);
return;
}
catch (error) {
@@ -679,22 +708,12 @@ class SingleSessionHTTPServer {
}
const accept = req.headers.accept;
if (accept && accept.includes('text/event-stream')) {
logger_1.logger.info('SSE stream request received - establishing SSE connection');
try {
await this.resetSessionSSE(res);
logger_1.logger.info('SSE connection established successfully');
}
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
});
}
logger_1.logger.info('SSE request on /mcp redirected to /sse', { ip: req.ip });
res.status(400).json({
error: 'SSE transport uses /sse endpoint',
message: 'Connect via GET /sse for SSE streaming. POST messages to /messages?sessionId=<id>.',
documentation: 'https://github.com/czlonkowski/n8n-mcp'
});
return;
}
if (process.env.N8N_MODE === 'true') {
@@ -719,9 +738,23 @@ class SingleSessionHTTPServer {
mcp: {
method: 'POST',
path: '/mcp',
description: 'Main MCP JSON-RPC endpoint',
description: 'Main MCP JSON-RPC endpoint (StreamableHTTP)',
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: {
method: 'GET',
path: '/health',
@@ -738,6 +771,92 @@ class SingleSessionHTTPServer {
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) => {
const mcpSessionId = req.headers['mcp-session-id'];
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) => {
logger_1.logger.info('POST /mcp request received - DETAILED DEBUG', {
headers: req.headers,
@@ -859,63 +949,10 @@ class SingleSessionHTTPServer {
req.removeListener('close', closeHandler);
});
}
const authHeader = req.headers.authorization;
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
});
if (!this.authenticateRequest(req, res))
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', {
hasSession: !!this.session,
sessionType: this.session?.isSSE ? 'SSE' : 'StreamableHTTP',
sessionInitialized: this.session?.initialized
activeSessions: this.getActiveSessionCount()
});
const instanceContext = (() => {
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(`Health check: ${endpoints.health}`);
console.log(`MCP endpoint: ${endpoints.mcp}`);
console.log(`SSE endpoint: ${baseUrl}/sse (legacy clients)`);
if (isProduction) {
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);
}
}
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) {
await new Promise((resolve) => {
this.expressServer.close(() => {
@@ -1085,22 +1113,8 @@ class SingleSessionHTTPServer {
}
getSessionInfo() {
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 {
active: true,
sessionId: this.session.sessionId,
age: Date.now() - this.session.lastAccess.getTime(),
active: metrics.activeSessions > 0,
sessions: {
total: metrics.totalSessions,
active: metrics.activeSessions,

File diff suppressed because one or more lines are too long

1
dist/index.d.ts vendored
View File

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

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

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAGzD,YAAY,EACV,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,YAAY,EACb,MAAM,uBAAuB,CAAC;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
View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAOA,2CAAyE;AAAhE,0GAAA,YAAY,OAAA;AACrB,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAChC,2DAAyD;AAAhD,iHAAA,cAAc,OAAA;AACvB,uCAAyD;AAAhD,mHAAA,yBAAyB,OAAA;AAMlC,6DAGkC;AAFhC,2HAAA,uBAAuB,OAAA;AACvB,qHAAA,iBAAiB,OAAA;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"}

View File

@@ -1,6 +1,7 @@
import { Request, Response } from 'express';
import { InstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
export interface EngineHealth {
status: 'healthy' | 'unhealthy';
uptime: number;
@@ -15,6 +16,7 @@ export interface EngineHealth {
export interface EngineOptions {
sessionTimeout?: number;
logLevel?: 'error' | 'warn' | 'info' | 'debug';
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export declare class N8NMCPEngine {
private server;

View File

@@ -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
View File

@@ -5,7 +5,9 @@ const http_server_single_session_1 = require("./http-server-single-session");
const logger_1 = require("./utils/logger");
class N8NMCPEngine {
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();
if (options.logLevel) {
process.env.LOG_LEVEL = options.logLevel;

View File

@@ -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":"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"}

View File

@@ -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 handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, 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 handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;

View File

@@ -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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"}

View File

@@ -56,6 +56,7 @@ exports.handleDiagnostic = handleDiagnostic;
exports.handleWorkflowVersions = handleWorkflowVersions;
exports.handleDeployTemplate = handleDeployTemplate;
exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow;
exports.tryParseJson = tryParseJson;
exports.handleCreateTable = handleCreateTable;
exports.handleListTables = handleListTables;
exports.handleGetTable = handleGetTable;
@@ -518,6 +519,24 @@ async function handleUpdateWorkflow(args, repository, context) {
if (updateData.nodes || updateData.connections) {
const current = await client.getWorkflow(id);
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) {
try {
const versioningService = new workflow_versioning_service_1.WorkflowVersioningService(repository, client);

File diff suppressed because one or more lines are too long

View File

@@ -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"}

View File

@@ -51,17 +51,19 @@ function getValidator(repository) {
return cachedValidator;
}
const NODE_TARGETING_OPERATIONS = new Set([
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode', 'patchNodeField'
]);
const workflowDiffSchema = zod_1.z.object({
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(),
description: zod_1.z.string().optional(),
node: zod_1.z.any().optional(),
nodeId: zod_1.z.string().optional(),
nodeName: zod_1.z.string().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(),
source: zod_1.z.string().optional(),
target: zod_1.z.string().optional(),
@@ -93,7 +95,7 @@ const workflowDiffSchema = zod_1.z.object({
}
}
return op;
})),
}))),
validateOnly: zod_1.z.boolean().optional(),
continueOnError: 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();
case 'updateNode':
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
case 'patchNodeField':
return `Patch field on node ${op.nodeName || op.nodeId || ''}`.trim();
case 'addConnection':
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
case 'removeConnection':
@@ -538,6 +542,10 @@ function inferIntentFromOperations(operations) {
const count = opTypes.filter((t) => t === 'updateNode').length;
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')) {
summary.push('modify connections');
}

File diff suppressed because one or more lines are too long

11
dist/mcp/server.d.ts vendored
View File

@@ -1,5 +1,9 @@
import { InstanceContext } from '../types/instance-context';
import { GenerateWorkflowHandler } from '../types/generate-workflow';
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
interface MCPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export declare class N8NDocumentationMCPServer {
private server;
private db;
@@ -16,7 +20,8 @@ export declare class N8NDocumentationMCPServer {
private useSharedDatabase;
private sharedDbState;
private isShutdown;
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger);
private generateWorkflowHandler?;
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger, options?: MCPServerOptions);
close(): Promise<void>;
private initializeDatabase;
private initializeInMemorySchema;
@@ -46,6 +51,7 @@ export declare class N8NDocumentationMCPServer {
private getNodeDocumentation;
private safeJsonParse;
private getDatabaseStatistics;
private buildOperationsTree;
private getNodeEssentials;
private getNode;
private handleInfoMode;
@@ -74,6 +80,8 @@ export declare class N8NDocumentationMCPServer {
private listNodeTemplates;
private getTemplate;
private searchTemplates;
private workflowPatternsCache;
private getWorkflowPatterns;
private getTemplatesForTask;
private searchTemplatesByMetadata;
private getTaskDescription;
@@ -83,4 +91,5 @@ export declare class N8NDocumentationMCPServer {
run(): Promise<void>;
shutdown(): Promise<void>;
}
export {};
//# sourceMappingURL=server.d.ts.map

View File

@@ -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
View File

@@ -72,7 +72,7 @@ const protocol_version_1 = require("../utils/protocol-version");
const telemetry_1 = require("../telemetry");
const startup_checkpoints_1 = require("../telemetry/startup-checkpoints");
class N8NDocumentationMCPServer {
constructor(instanceContext, earlyLogger) {
constructor(instanceContext, earlyLogger, options) {
this.db = null;
this.repository = null;
this.templateService = null;
@@ -86,8 +86,10 @@ class N8NDocumentationMCPServer {
this.sharedDbState = null;
this.isShutdown = false;
this.dbHealthChecked = false;
this.workflowPatternsCache = null;
this.instanceContext = instanceContext;
this.earlyLogger = earlyLogger || null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
const envDbPath = process.env.NODE_DB_PATH;
let dbPath = null;
let possiblePaths = [];
@@ -499,6 +501,9 @@ class N8NDocumentationMCPServer {
}
}
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
if (processedArgs) {
processedArgs = JSON.parse(JSON.stringify(processedArgs));
}
try {
logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs });
const startTime = Date.now();
@@ -931,6 +936,7 @@ class N8NDocumentationMCPServer {
return this.searchNodes(args.query, limit, {
mode: args.mode,
includeExamples: args.includeExamples,
includeOperations: args.includeOperations,
source: args.source
});
case 'get_node':
@@ -1022,6 +1028,8 @@ class N8NDocumentationMCPServer {
requiredService: args.requiredService,
targetAudience: args.targetAudience
}, searchLimit, searchOffset);
case 'patterns':
return this.getWorkflowPatterns(args.task, searchLimit);
case 'keyword':
default:
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`);
}
}
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:
throw new Error(`Unknown tool: ${name}`);
}
@@ -1270,7 +1316,7 @@ class N8NDocumentationMCPServer {
return { query, results: [], totalCount: 0 };
}
if (mode === 'FUZZY') {
return this.searchNodesFuzzy(cleanedQuery, limit);
return this.searchNodesFuzzy(cleanedQuery, limit, { includeOperations: options?.includeOperations });
}
let ftsQuery;
if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) {
@@ -1338,7 +1384,7 @@ class N8NDocumentationMCPServer {
const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest');
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
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 = {
query,
@@ -1362,6 +1408,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads;
}
}
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult;
}),
totalCount: scoredNodes.length
@@ -1412,7 +1464,7 @@ class N8NDocumentationMCPServer {
return this.searchNodesLIKE(query, limit);
}
}
async searchNodesFuzzy(query, limit) {
async searchNodesFuzzy(query, limit, options) {
if (!this.db)
throw new Error('Database not initialized');
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
@@ -1440,14 +1492,23 @@ class N8NDocumentationMCPServer {
return {
query,
mode: 'FUZZY',
results: matchingNodes.map(node => ({
nodeType: node.node_type,
workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type),
displayName: node.display_name,
description: node.description,
category: node.category,
package: node.package_name
})),
results: matchingNodes.map(node => {
const nodeResult = {
nodeType: node.node_type,
workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type),
displayName: node.display_name,
description: node.description,
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
};
}
@@ -1568,6 +1629,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads;
}
}
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult;
}),
totalCount: rankedNodes.length
@@ -1635,6 +1702,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads;
}
}
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult;
}),
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) {
await this.ensureInitialized();
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}.`
};
}
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) {
await this.ensureInitialized();
if (!this.templateService)

File diff suppressed because one or more lines are too long

View File

@@ -29,6 +29,16 @@ console.table = () => { };
console.clear = () => { };
console.count = () => { };
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");
let server = null;
async function main() {

View File

@@ -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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"}

View File

@@ -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"}

View File

@@ -6,7 +6,7 @@ exports.searchNodesDoc = {
category: 'discovery',
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.',
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples'],
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples', 'includeOperations'],
example: 'search_nodes({query: "webhook"})',
performance: '<20ms even for complex queries',
tips: [
@@ -15,7 +15,8 @@ exports.searchNodesDoc = {
'FUZZY mode: Handles typos and spelling errors',
'Use quotes for exact phrases: "google sheets"',
'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: {
@@ -25,20 +26,17 @@ exports.searchNodesDoc = {
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 },
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.',
examples: [
'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: "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: "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 (7 resources, 44 ops)'
],
useCases: [
'Finding nodes when you know partial names',

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -30,6 +30,7 @@ exports.toolsDocumentation = {
n8n_executions: workflow_management_1.n8nExecutionsDoc,
n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc,
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

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -5,7 +5,7 @@ exports.searchTemplatesDoc = {
name: 'search_templates',
category: 'templates',
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'],
example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})',
performance: 'Fast (<100ms) - FTS5 full-text search',
@@ -13,7 +13,9 @@ exports.searchTemplatesDoc = {
'searchMode="keyword" (default): Search by name/description',
'searchMode="by_nodes": Find templates using specific nodes',
'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: {
@@ -22,14 +24,15 @@ exports.searchTemplatesDoc = {
- by_nodes: Find templates that use specific node types
- by_task: Get curated templates for predefined task categories
- 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`,
parameters: {
searchMode: {
type: 'string',
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: {
type: 'string',
@@ -44,7 +47,7 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
task: {
type: 'string',
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: {
type: 'string',
@@ -92,38 +95,45 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
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
- id: Template ID for get_template()
- name: Template name
- 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.)
- name, description, author, nodes, views, created, url, metadata
- 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: [
'// 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"]})',
'// 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"})',
'// 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: [
'Find workflows by business purpose (keyword search)',
'Find templates using specific integrations (by_nodes)',
'Get pre-built solutions for common tasks (by_task)',
'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:
- keyword: <50ms with FTS5 indexing
- by_nodes: <100ms with indexed lookups
- 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: [
'Use searchMode="by_task" for common automation patterns',
'Use searchMode="by_nodes" when you know which integrations you need',

View File

@@ -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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"}

View File

@@ -11,4 +11,5 @@ export { n8nExecutionsDoc } from './n8n-executions';
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
export { n8nDeployTemplateDoc } from './n8n-deploy-template';
export { n8nManageDatatableDoc } from './n8n-manage-datatable';
export { n8nGenerateWorkflowDoc } from './n8n-generate-workflow';
//# sourceMappingURL=index.d.ts.map

View File

@@ -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"}

View File

@@ -1,6 +1,6 @@
"use strict";
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");
Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } });
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; } });
var n8n_manage_datatable_1 = require("./n8n-manage-datatable");
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

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -5,7 +5,7 @@ exports.n8nUpdatePartialWorkflowDoc = {
name: 'n8n_update_partial_workflow',
category: 'workflow_management',
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'],
example: 'n8n_update_partial_workflow({id: "wf_123", operations: [{type: "rewireConnection", source: "IF", from: "Old", to: "New", branch: "true"}]})',
performance: 'Fast (50-200ms)',
@@ -28,14 +28,15 @@ exports.n8nUpdatePartialWorkflowDoc = {
]
},
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:
### Node Operations (6 types):
### Node Operations (7 types):
- **addNode**: Add a new node with name, type, and position (required)
- **removeNode**: Remove a node by ID or name
- **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]
- **enableNode**: Enable a disabled 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})',
'// 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"}]}}}]})',
'\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 ============',
'// 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"}]})',
@@ -374,7 +380,10 @@ n8n_update_partial_workflow({
'Configure Vector Store retrieval systems',
'Swap language models in existing AI workflows',
'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.',
bestPractices: [
@@ -397,7 +406,10 @@ n8n_update_partial_workflow({
'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',
'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: [
'**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',
'**__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',
'**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',
'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',

View File

@@ -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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"}

View File

@@ -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"}

View File

@@ -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_workflow({workflow: {...}}) - Validate entire workflow
## Tool Categories (19 Tools Total)
## Tool Categories (21 Tools Total)
**Discovery Tools** (1 tool)
- search_nodes - Full-text search across all nodes (supports OR, AND, FUZZY modes)
@@ -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_task': Curated task-based templates
- searchMode='by_metadata': Filter by complexity/services
- searchMode='patterns': Workflow pattern summaries from 2,700+ templates
**n8n API Tools** (13 tools, requires N8N_API_URL configuration)
**n8n API Tools** (15 tools, requires N8N_API_URL configuration)
- n8n_create_workflow - Create new workflows
- n8n_get_workflow - Get workflow with mode='full'/'details'/'structure'/'minimal'
- n8n_update_full_workflow - Full workflow replacement
@@ -136,6 +137,8 @@ When working with Code nodes, always start by calling the relevant guide:
- n8n_health_check - Check n8n API connectivity
- n8n_workflow_versions - Version history and rollback
- n8n_deploy_template - Deploy templates directly to n8n instance
- n8n_manage_datatable - Manage data tables and rows
- n8n_generate_workflow - Generate workflow from natural language description
## Performance Characteristics
- Instant (<10ms): search_nodes, get_node (minimal/standard)

View File

@@ -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":"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"}

View File

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

View File

@@ -141,7 +141,7 @@ exports.n8nManagementTools = [
},
{
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: {
type: 'object',
additionalProperties: true,
@@ -635,5 +635,45 @@ exports.n8nManagementTools = [
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

File diff suppressed because one or more lines are too long

View File

@@ -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
View File

@@ -52,6 +52,11 @@ exports.n8nDocumentationToolsFinal = [
description: 'Include top 2 real-world configuration examples from popular templates (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: {
type: 'string',
enum: ['all', 'core', 'community', 'verified'],
@@ -237,14 +242,14 @@ exports.n8nDocumentationToolsFinal = [
},
{
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: {
type: 'object',
properties: {
searchMode: {
type: 'string',
enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata'],
description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services',
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, patterns=lightweight workflow pattern summaries',
default: 'keyword',
},
query: {
@@ -278,7 +283,7 @@ exports.n8nDocumentationToolsFinal = [
'api_integration',
'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: {
type: 'string',

File diff suppressed because one or more lines are too long

View File

@@ -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"}

View File

@@ -95,13 +95,17 @@ class PropertyExtractor {
}
}
if (description.properties && Array.isArray(description.properties)) {
const operationProp = description.properties.find((p) => p.name === 'operation' || p.name === 'action');
if (operationProp?.options) {
const operationProps = description.properties.filter((p) => p.name === 'operation' || p.name === 'action');
for (const operationProp of operationProps) {
if (!operationProp?.options)
continue;
const resource = operationProp.displayOptions?.show?.resource?.[0];
operationProp.options.forEach((op) => {
operations.push({
operation: op.value,
name: op.name,
description: op.description
description: op.description,
...(resource ? { resource } : {})
});
});
}

File diff suppressed because one or more lines are too long

View File

@@ -12,6 +12,7 @@ interface ExpressionContext {
hasInputData?: boolean;
}
export declare class ExpressionValidator {
private static readonly BARE_EXPRESSION_PATTERNS;
private static readonly EXPRESSION_PATTERN;
private static readonly VARIABLE_PATTERNS;
static validateExpression(expression: string, context: ExpressionContext): ExpressionValidationResult;
@@ -21,6 +22,7 @@ export declare class ExpressionValidator {
private static checkCommonMistakes;
private static checkNodeReferences;
static validateNodeExpressions(parameters: any, context: ExpressionContext): ExpressionValidationResult;
private static checkBareExpression;
private static validateParametersRecursive;
}
export {};

View File

@@ -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"}

View File

@@ -134,6 +134,20 @@ class ExpressionValidator {
combinedResult.valid = combinedResult.errors.length === 0;
return combinedResult;
}
static checkBareExpression(value, path, result) {
if (value.includes('{{') || value.startsWith('=')) {
return;
}
const trimmed = value.trim();
for (const { pattern, name } of this.BARE_EXPRESSION_PATTERNS) {
if (pattern.test(trimmed)) {
result.warnings.push((path ? `${path}: ` : '') +
`Possible unwrapped expression: "${trimmed}" looks like an n8n ${name} reference. ` +
`Use "={{ ${trimmed} }}" to evaluate it as an expression.`);
return;
}
}
}
static validateParametersRecursive(obj, context, result, path = '', visited = new WeakSet()) {
if (obj && typeof obj === 'object') {
if (visited.has(obj)) {
@@ -142,6 +156,7 @@ class ExpressionValidator {
visited.add(obj);
}
if (typeof obj === 'string') {
this.checkBareExpression(obj, path, result);
if (obj.includes('{{')) {
const validation = this.validateExpression(obj, context);
validation.errors.forEach(error => {
@@ -168,6 +183,16 @@ class ExpressionValidator {
}
}
exports.ExpressionValidator = ExpressionValidator;
ExpressionValidator.BARE_EXPRESSION_PATTERNS = [
{ pattern: /^\$json[.\[]/, name: '$json' },
{ pattern: /^\$node\[/, name: '$node' },
{ pattern: /^\$input\./, name: '$input' },
{ pattern: /^\$execution\./, name: '$execution' },
{ pattern: /^\$workflow\./, name: '$workflow' },
{ pattern: /^\$prevNode\./, name: '$prevNode' },
{ pattern: /^\$env\./, name: '$env' },
{ pattern: /^\$(now|today|itemIndex|runIndex)$/, name: 'built-in variable' },
];
ExpressionValidator.EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g;
ExpressionValidator.VARIABLE_PATTERNS = {
json: /\$json(\.[a-zA-Z_][\w]*|\["[^"]+"\]|\['[^']+'\]|\[\d+\])*/g,

File diff suppressed because one or more lines are too long

View File

@@ -30,10 +30,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
maxTries?: number | undefined;
waitBetweenTries?: number | undefined;
alwaysOutputData?: boolean | undefined;
executeOnce?: boolean | undefined;
disabled?: boolean | undefined;
notes?: string | undefined;
notesInFlow?: boolean | undefined;
executeOnce?: boolean | undefined;
}, {
type: string;
id: string;
@@ -47,10 +47,10 @@ export declare const workflowNodeSchema: z.ZodObject<{
maxTries?: number | undefined;
waitBetweenTries?: number | undefined;
alwaysOutputData?: boolean | undefined;
executeOnce?: boolean | undefined;
disabled?: boolean | undefined;
notes?: string | undefined;
notesInFlow?: boolean | undefined;
executeOnce?: boolean | undefined;
}>;
export declare const workflowConnectionSchema: z.ZodRecord<z.ZodString, 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 validateWorkflowStructure(workflow: Partial<Workflow>): string[];
export declare function hasWebhookTrigger(workflow: Workflow): boolean;
export declare function validateConditionNodeStructure(node: WorkflowNode): string[];
export declare function validateFilterBasedNodeMetadata(node: WorkflowNode): string[];
export declare function validateOperatorStructure(operator: any, path: string): string[];
export declare function getWebhookUrl(workflow: Workflow): string | null;

View File

@@ -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"}

View File

@@ -11,6 +11,7 @@ exports.cleanWorkflowForCreate = cleanWorkflowForCreate;
exports.cleanWorkflowForUpdate = cleanWorkflowForUpdate;
exports.validateWorkflowStructure = validateWorkflowStructure;
exports.hasWebhookTrigger = hasWebhookTrigger;
exports.validateConditionNodeStructure = validateConditionNodeStructure;
exports.validateFilterBasedNodeMetadata = validateFilterBasedNodeMetadata;
exports.validateOperatorStructure = validateOperatorStructure;
exports.getWebhookUrl = getWebhookUrl;
@@ -229,7 +230,7 @@ function validateWorkflowStructure(workflow) {
}
if (workflow.nodes) {
workflow.nodes.forEach((node, index) => {
const filterErrors = validateFilterBasedNodeMetadata(node);
const filterErrors = validateConditionNodeStructure(node);
if (filterErrors.length > 0) {
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' ||
node.type === 'n8n-nodes-base.webhookTrigger');
}
function validateFilterBasedNodeMetadata(node) {
function validateConditionNodeStructure(node) {
const errors = [];
const isIFNode = node.type === 'n8n-nodes-base.if' && node.typeVersion >= 2.2;
const isSwitchNode = node.type === 'n8n-nodes-base.switch' && node.typeVersion >= 3.2;
if (!isIFNode && !isSwitchNode) {
return errors;
}
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"}');
const typeVersion = node.typeVersion || 1;
if (node.type === 'n8n-nodes-base.if') {
if (typeVersion >= 2.2) {
errors.push(...validateFilterOptionsRequired(node.parameters?.conditions, 'conditions'));
errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
}
else {
const requiredFields = {
version: 2,
leftValue: '',
caseSensitive: 'boolean',
typeValidation: 'strict'
};
for (const [field, expectedValue] of Object.entries(requiredFields)) {
if (!(field in conditions.options)) {
errors.push(`Missing required field "conditions.options.${field}". ` +
`Expected value: ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue}`);
}
else if (typeVersion >= 2) {
errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
}
}
else if (node.type === 'n8n-nodes-base.switch') {
if (typeVersion >= 3.2) {
const rules = node.parameters?.rules;
if (rules?.rules && Array.isArray(rules.rules)) {
rules.rules.forEach((rule, i) => {
errors.push(...validateFilterOptionsRequired(rule.conditions, `rules.rules[${i}].conditions`));
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;
}
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) {
const errors = [];
if (!operator || typeof operator !== 'object') {

File diff suppressed because one or more lines are too long

View File

@@ -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"}

View File

@@ -1317,12 +1317,16 @@ class NodeSpecificValidators {
}
}
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) {
warnings.push({
type: 'missing_common',
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

View File

@@ -14,6 +14,7 @@ export declare class WorkflowDiffEngine {
private validateAddNode;
private validateRemoveNode;
private validateUpdateNode;
private validatePatchNodeField;
private validateMoveNode;
private validateToggleNode;
private validateAddConnection;
@@ -22,6 +23,7 @@ export declare class WorkflowDiffEngine {
private applyAddNode;
private applyRemoveNode;
private applyUpdateNode;
private applyPatchNodeField;
private applyMoveNode;
private applyEnableNode;
private applyDisableNode;

View File

@@ -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"}

View File

@@ -6,6 +6,39 @@ const logger_1 = require("../utils/logger");
const node_sanitizer_1 = require("./node-sanitizer");
const node_type_utils_1 = require("../utils/node-type-utils");
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 {
constructor() {
this.renameMap = new Map();
@@ -25,7 +58,7 @@ class WorkflowDiffEngine {
this.tagsToRemove = [];
this.transferToProjectId = undefined;
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 otherOperations = [];
request.operations.forEach((operation, index) => {
@@ -213,6 +246,8 @@ class WorkflowDiffEngine {
return this.validateRemoveNode(workflow, operation);
case 'updateNode':
return this.validateUpdateNode(workflow, operation);
case 'patchNodeField':
return this.validatePatchNodeField(workflow, operation);
case 'moveNode':
return this.validateMoveNode(workflow, operation);
case 'enableNode':
@@ -254,6 +289,9 @@ class WorkflowDiffEngine {
case 'updateNode':
this.applyUpdateNode(workflow, operation);
break;
case 'patchNodeField':
this.applyPatchNodeField(workflow, operation);
break;
case 'moveNode':
this.applyMoveNode(workflow, operation);
break;
@@ -375,6 +413,63 @@ class WorkflowDiffEngine {
}
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) {
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node) {
@@ -586,6 +681,51 @@ class WorkflowDiffEngine {
const sanitized = (0, node_sanitizer_1.sanitizeNode)(node);
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) {
const node = this.findNode(workflow, operation.nodeId, operation.nodeName);
if (!node)
@@ -924,6 +1064,8 @@ class WorkflowDiffEngine {
const keys = path.split('.');
let current = obj;
for (const key of keys) {
if (DANGEROUS_PATH_KEYS.has(key))
return undefined;
if (current == null || typeof current !== 'object')
return undefined;
current = current[key];
@@ -933,6 +1075,9 @@ class WorkflowDiffEngine {
setNestedProperty(obj, path, value) {
const keys = path.split('.');
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++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {

File diff suppressed because one or more lines are too long

View File

@@ -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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"}

View File

@@ -14,6 +14,7 @@ const ai_node_validator_1 = require("./ai-node-validator");
const ai_tool_validators_1 = require("./ai-tool-validators");
const node_type_utils_1 = require("../utils/node-type-utils");
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 logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' });
exports.VALID_CONNECTION_TYPES = new Set([
@@ -367,6 +368,17 @@ class WorkflowValidator {
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) {
result.errors.push({

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ export * from './node-types';
export * from './type-structures';
export * from './instance-context';
export * from './session-state';
export * from './generate-workflow';
export interface MCPServerConfig {
port: number;
host: string;

View File

@@ -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
View File

@@ -18,4 +18,5 @@ __exportStar(require("./node-types"), exports);
__exportStar(require("./type-structures"), exports);
__exportStar(require("./instance-context"), exports);
__exportStar(require("./session-state"), exports);
__exportStar(require("./generate-workflow"), exports);
//# sourceMappingURL=index.js.map

View File

@@ -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"}

View File

@@ -40,6 +40,18 @@ export interface DisableNodeOperation extends DiffOperation {
nodeId?: 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 {
type: 'addConnection';
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 {
id: string;
operations: WorkflowDiffOperation[];
@@ -149,7 +161,7 @@ export interface NodeReference {
id?: 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 isMetadataOperation(op: WorkflowDiffOperation): op is UpdateSettingsOperation | UpdateNameOperation | AddTagOperation | RemoveTagOperation;
//# sourceMappingURL=workflow-diff.d.ts.map

View File

@@ -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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"}

View File

@@ -4,7 +4,7 @@ exports.isNodeOperation = isNodeOperation;
exports.isConnectionOperation = isConnectionOperation;
exports.isMetadataOperation = isMetadataOperation;
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) {
return ['addConnection', 'removeConnection', 'rewireConnection', 'cleanStaleConnections', 'replaceConnections'].includes(op.type);

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp",
"version": "2.42.2",
"version": "2.46.1",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -12,7 +12,7 @@
}
},
"bin": {
"n8n-mcp": "./dist/mcp/index.js"
"n8n-mcp": "./dist/mcp/stdio-wrapper.js"
},
"scripts": {
"build": "tsc -p tsconfig.build.json",
@@ -140,27 +140,27 @@
"@vitest/coverage-v8": "^3.2.4",
"@vitest/runner": "^3.2.4",
"@vitest/ui": "^3.2.4",
"axios": "^1.11.0",
"axios": "^1.14.0",
"axios-mock-adapter": "^2.1.0",
"fishery": "^2.3.1",
"msw": "^2.10.4",
"nodemon": "^3.1.10",
"nodemon": "^3.1.14",
"ts-node": "^10.9.2",
"typescript": "^5.8.3",
"vitest": "^3.2.4"
},
"dependencies": {
"@modelcontextprotocol/sdk": "1.28.0",
"@n8n/n8n-nodes-langchain": "^2.13.1",
"@n8n/n8n-nodes-langchain": "^2.14.1",
"@supabase/supabase-js": "^2.57.4",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"express-rate-limit": "^7.1.5",
"form-data": "^4.0.5",
"lru-cache": "^11.2.1",
"n8n": "^2.13.3",
"n8n-core": "^2.13.1",
"n8n-workflow": "^2.13.1",
"n8n": "^2.14.2",
"n8n-core": "^2.14.1",
"n8n-workflow": "^2.14.1",
"openai": "^4.77.0",
"sql.js": "^1.13.0",
"tslib": "^2.6.2",

View File

@@ -1,6 +1,6 @@
{
"name": "n8n-mcp-runtime",
"version": "2.33.2",
"version": "2.46.0",
"description": "n8n MCP Server Runtime Dependencies Only",
"private": true,
"dependencies": {

View File

@@ -35,7 +35,7 @@ node -e "
const pkg = require('./package.json');
pkg.name = 'n8n-mcp';
pkg.description = 'Integration between n8n workflow automation and Model Context Protocol (MCP)';
pkg.bin = { 'n8n-mcp': './dist/mcp/index.js' };
pkg.bin = { 'n8n-mcp': './dist/mcp/stdio-wrapper.js' };
pkg.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';

View File

@@ -68,7 +68,7 @@ pkg.exports = {
import: './dist/index.js'
}
};
pkg.bin = { 'n8n-mcp': './dist/mcp/index.js' };
pkg.bin = { 'n8n-mcp': './dist/mcp/stdio-wrapper.js' };
pkg.repository = { type: 'git', url: 'git+https://github.com/czlonkowski/n8n-mcp.git' };
pkg.keywords = ['n8n', 'mcp', 'model-context-protocol', 'ai', 'workflow', 'automation'];
pkg.author = 'Romuald Czlonkowski @ www.aiadvisors.pl/en';

View File

@@ -26,6 +26,7 @@ import {
} from './utils/protocol-version';
import { InstanceContext, validateInstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
import { closeSharedDatabase } from './database/shared-database';
dotenv.config();
@@ -45,15 +46,6 @@ interface MultiTenantHeaders {
const MAX_SESSIONS = Math.max(1, parseInt(process.env.N8N_MCP_MAX_SESSIONS || '100', 10));
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 {
totalSessions: number;
activeSessions: number;
@@ -97,14 +89,18 @@ function logSecurityEvent(
logger.info(`[SECURITY] ${event}`, logEntry);
}
export interface SingleSessionHTTPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export class SingleSessionHTTPServer {
// Map to store transports by session ID (following SDK pattern)
private transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
// Stores both StreamableHTTP and SSE transports; use instanceof to discriminate
private transports: { [sessionId: string]: StreamableHTTPServerTransport | SSEServerTransport } = {};
private servers: { [sessionId: string]: N8NDocumentationMCPServer } = {};
private sessionMetadata: { [sessionId: string]: { lastAccess: Date; createdAt: Date } } = {};
private sessionContexts: { [sessionId: string]: InstanceContext | undefined } = {};
private contextSwitchLocks: Map<string, Promise<void>> = new Map();
private session: Session | null = null; // Keep for SSE compatibility
private consoleManager = new ConsoleManager();
private expressServer: any;
// Session timeout — configurable via SESSION_TIMEOUT_MINUTES environment variable
@@ -114,8 +110,10 @@ export class SingleSessionHTTPServer {
) * 60 * 1000;
private authToken: string | null = null;
private cleanupTimer: NodeJS.Timeout | null = null;
constructor() {
private generateWorkflowHandler?: GenerateWorkflowHandler;
constructor(options?: SingleSessionHTTPServerOptions) {
this.generateWorkflowHandler = options?.generateWorkflowHandler;
// Validate environment on construction
this.validateEnvironment();
// No longer pre-create session - will be created per initialize request following SDK pattern
@@ -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
*/
@@ -565,8 +606,10 @@ export class SingleSessionHTTPServer {
sessionIdToUse = sessionId || uuidv4();
}
const server = new N8NDocumentationMCPServer(instanceContext);
const server = new N8NDocumentationMCPServer(instanceContext, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => sessionIdToUse,
onsessioninitialized: (initializedSessionId: string) => {
@@ -627,7 +670,22 @@ export class SingleSessionHTTPServer {
// For non-initialize requests: reuse existing transport for this session
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
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> {
// Clean up old session if exists
if (this.session) {
const sessionId = this.session.sessionId;
logger.info('Closing previous session for SSE', { sessionId });
// Close server first to free resources (database, cache timer, etc.)
// 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 });
}
private async createSSESession(res: express.Response): Promise<void> {
if (!this.canCreateSession()) {
logger.warn('SSE session creation rejected: session limit reached', {
currentSessions: this.getActiveSessionCount(),
maxSessions: MAX_SESSIONS
});
throw new Error(`Session limit reached (${MAX_SESSIONS})`);
}
try {
// Create new session
logger.info('Creating new N8NDocumentationMCPServer for SSE...');
const server = new N8NDocumentationMCPServer();
// Generate cryptographically secure session ID
const sessionId = uuidv4();
logger.info('Creating SSEServerTransport...');
const transport = new SSEServerTransport('/mcp', res);
logger.info('Connecting server to SSE transport...');
await server.connect(transport);
// Note: server.connect() automatically calls transport.start(), so we don't need to call it again
this.session = {
server,
transport,
lastAccess: new Date(),
sessionId,
initialized: false,
isSSE: true
};
logger.info('Created new SSE session successfully', { sessionId: this.session.sessionId });
} catch (error) {
logger.error('Failed to create SSE session:', error);
throw error;
}
}
/**
* Check if current session is expired
*/
private isExpired(): boolean {
if (!this.session) return true;
return Date.now() - this.session.lastAccess.getTime() > this.sessionTimeout;
// Note: SSE sessions do not support multi-tenant context.
// The SaaS backend uses StreamableHTTP exclusively.
const server = new N8NDocumentationMCPServer(undefined, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
const transport = new SSEServerTransport('/messages', res);
// Use the SDK-assigned session ID — the client receives this via the SSE
// `endpoint` event and sends it back as ?sessionId on POST /messages.
const sessionId = transport.sessionId;
this.transports[sessionId] = transport;
this.servers[sessionId] = server;
this.sessionMetadata[sessionId] = {
lastAccess: new Date(),
createdAt: new Date()
};
// Clean up on SSE disconnect
res.on('close', () => {
logger.info('SSE connection closed by client', { sessionId });
this.removeSession(sessionId, 'sse_disconnect').catch(err => {
logger.warn('Error cleaning up SSE session on disconnect', { sessionId, error: err });
});
});
await server.connect(transport);
logger.info('SSE session created', { sessionId, transport: 'SSEServerTransport' });
}
/**
@@ -902,7 +936,7 @@ export class SingleSessionHTTPServer {
authentication: {
type: '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'
});
@@ -937,7 +971,7 @@ export class SingleSessionHTTPServer {
},
activeTransports: activeTransports.length, // Legacy field
activeServers: activeServers.length, // Legacy field
legacySessionActive: !!this.session, // For SSE compatibility
legacySessionActive: false, // Deprecated: SSE now uses shared transports map
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
@@ -994,10 +1028,11 @@ export class SingleSessionHTTPServer {
app.get('/mcp', async (req, res) => {
// Handle StreamableHTTP transport requests with new pattern
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
try {
await this.transports[sessionId].handleRequest(req, res, undefined);
await existingTransport.handleRequest(req, res, undefined);
return;
} catch (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;
if (accept && accept.includes('text/event-stream')) {
logger.info('SSE stream request received - establishing SSE connection');
try {
// Create or reset session for SSE
await this.resetSessionSSE(res);
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
});
}
logger.info('SSE request on /mcp redirected to /sse', { ip: req.ip });
res.status(400).json({
error: 'SSE transport uses /sse endpoint',
message: 'Connect via GET /sse for SSE streaming. POST messages to /messages?sessionId=<id>.',
documentation: 'https://github.com/czlonkowski/n8n-mcp'
});
return;
}
@@ -1061,9 +1085,23 @@ export class SingleSessionHTTPServer {
mcp: {
method: 'POST',
path: '/mcp',
description: 'Main MCP JSON-RPC endpoint',
description: 'Main MCP JSON-RPC endpoint (StreamableHTTP)',
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: {
method: 'GET',
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
app.delete('/mcp', async (req: express.Request, res: express.Response): Promise<void> => {
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
app.post('/mcp', authLimiter, jsonParser, async (req: express.Request, res: express.Response): Promise<void> => {
// Log comprehensive debug info about the request
@@ -1223,76 +1331,10 @@ export class SingleSessionHTTPServer {
});
}
// Enhanced authentication check with specific logging
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();
if (!this.authenticateRequest(req, res)) return;
// 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', {
hasSession: !!this.session,
sessionType: this.session?.isSSE ? 'SSE' : 'StreamableHTTP',
sessionInitialized: this.session?.initialized
activeSessions: this.getActiveSessionCount()
});
// 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(`Health check: ${endpoints.health}`);
console.log(`MCP endpoint: ${endpoints.mcp}`);
console.log(`SSE endpoint: ${baseUrl}/sse (legacy clients)`);
if (isProduction) {
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
if (this.expressServer) {
await new Promise<void>((resolve) => {
@@ -1521,25 +1553,9 @@ export class SingleSessionHTTPServer {
};
} {
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 {
active: true,
sessionId: this.session.sessionId,
age: Date.now() - this.session.lastAccess.getTime(),
active: metrics.activeSessions > 0,
sessions: {
total: metrics.totalSessions,
active: metrics.activeSessions,

View File

@@ -21,6 +21,13 @@ export {
export type {
SessionState
} from './types/session-state';
export type {
GenerateWorkflowArgs,
GenerateWorkflowResult,
GenerateWorkflowProposal,
GenerateWorkflowHandler,
GenerateWorkflowHelpers
} from './types/generate-workflow';
// UI module exports
export type { UIAppConfig, UIMetadata } from './mcp/ui/types';

View File

@@ -10,6 +10,7 @@ import { SingleSessionHTTPServer } from './http-server-single-session';
import { logger } from './utils/logger';
import { InstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
export interface EngineHealth {
status: 'healthy' | 'unhealthy';
@@ -26,6 +27,7 @@ export interface EngineHealth {
export interface EngineOptions {
sessionTimeout?: number;
logLevel?: 'error' | 'warn' | 'info' | 'debug';
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export class N8NMCPEngine {
@@ -33,9 +35,11 @@ export class N8NMCPEngine {
private startTime: Date;
constructor(options: EngineOptions = {}) {
this.server = new SingleSessionHTTPServer();
this.server = new SingleSessionHTTPServer({
generateWorkflowHandler: options.generateWorkflowHandler,
});
this.startTime = new Date();
if (options.logLevel) {
process.env.LOG_LEVEL = options.logLevel;
}

View File

@@ -776,6 +776,28 @@ export async function handleUpdateWorkflow(
const current = await client.getWorkflow(id);
workflowBefore = JSON.parse(JSON.stringify(current));
// Preserve credentials from current workflow for nodes that don't specify them.
// AI-generated node updates typically omit credential references because they
// aren't included in the context provided to the AI. Without this merge, the
// n8n API rejects the PUT with missing credentials.
if (updateData.nodes && current.nodes) {
const currentById = new Map<string, any>();
const currentByName = new Map<string, any>();
for (const node of current.nodes) {
if (node.id) currentById.set(node.id, node);
currentByName.set(node.name, node);
}
for (const node of updateData.nodes as any[]) {
const hasCredentials = node.credentials && typeof node.credentials === 'object' && Object.keys(node.credentials).length > 0;
if (!hasCredentials) {
const match = (node.id && currentById.get(node.id)) || currentByName.get(node.name);
if (match?.credentials) {
node.credentials = match.credentials;
}
}
}
}
// Create backup before modifying workflow (default: true)
if (createBackup !== false) {
try {

View File

@@ -33,7 +33,7 @@ function getValidator(repository: NodeRepository): WorkflowValidator {
// Operation types that identify nodes by nodeId/nodeName
const NODE_TARGETING_OPERATIONS = new Set([
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode'
'updateNode', 'removeNode', 'moveNode', 'enableNode', 'disableNode', 'patchNodeField'
]);
// Zod schema for the diff request
@@ -47,6 +47,8 @@ const workflowDiffSchema = z.object({
nodeId: z.string().optional(),
nodeName: z.string().optional(),
updates: z.any().optional(),
fieldPath: z.string().optional(),
patches: z.any().optional(),
position: z.tuple([z.number(), z.number()]).optional(),
// Connection operations
source: z.string().optional(),
@@ -569,6 +571,8 @@ function inferIntentFromOperations(operations: any[]): string {
return `Remove node ${op.nodeName || op.nodeId || ''}`.trim();
case 'updateNode':
return `Update node ${op.nodeName || op.nodeId || ''}`.trim();
case 'patchNodeField':
return `Patch field on node ${op.nodeName || op.nodeId || ''}`.trim();
case 'addConnection':
return `Connect ${op.source || 'node'} to ${op.target || 'node'}`;
case 'removeConnection':
@@ -604,6 +608,10 @@ function inferIntentFromOperations(operations: any[]): string {
const count = opTypes.filter((t) => t === 'updateNode').length;
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')) {
summary.push('modify connections');
}

View File

@@ -41,6 +41,7 @@ import {
STANDARD_PROTOCOL_VERSION
} from '../utils/protocol-version';
import { InstanceContext } from '../types/instance-context';
import { GenerateWorkflowHandler, GenerateWorkflowHelpers } from '../types/generate-workflow';
import { telemetry } from '../telemetry';
import { EarlyErrorLogger } from '../telemetry/early-error-logger';
import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints';
@@ -141,6 +142,10 @@ interface VersionComparisonInfo {
type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo;
interface MCPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export class N8NDocumentationMCPServer {
private server: Server;
private db: DatabaseAdapter | null = null;
@@ -157,10 +162,12 @@ export class N8NDocumentationMCPServer {
private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup
private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release
private isShutdown: boolean = false; // Prevent double-shutdown
private generateWorkflowHandler?: GenerateWorkflowHandler;
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger) {
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger, options?: MCPServerOptions) {
this.instanceContext = instanceContext;
this.earlyLogger = earlyLogger || null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
// Check for test environment first
const envDbPath = process.env.NODE_DB_PATH;
let dbPath: string | null = null;
@@ -1531,6 +1538,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:
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!;
if (category) {
// Return specific category pattern data
// Return specific category pattern data (trimmed for token efficiency)
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,
...categoryData,
nodes: categoryData.nodes?.slice(0, limit),
commonChains: categoryData.commonChains?.slice(0, limit),
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
})),
};
}

View File

@@ -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 },
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 },
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.',
examples: [
'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: "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: "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", 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: [
'Finding nodes when you know partial names',

Some files were not shown because too many files have changed in this diff Show More