Compare commits

..

17 Commits

Author SHA1 Message Date
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
czlonkowski
49638b98cf fix: include workflow-patterns.json in npm package (#681)
Added data/workflow-patterns.json to the files array in package.json so
the patterns file ships with the npm package. Without this, the
search_templates patterns mode returns an error asking users to manually
run the mine script.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:59:52 +02:00
Romuald Członkowski
fa766eff3c Merge pull request #680 from czlonkowski/fix/community-node-resource-grouping 2026-03-30 20:56:48 +02:00
czlonkowski
b890bd9601 fix: restore community nodes with resource-grouped operations (v2.42.1)
- Restore 584 community nodes from n8n 2.13.3 DB snapshot
- Re-extract operations from properties_schema with resource grouping
  (366 community nodes now have named resources, up from 10)
- Fix community-node-service.ts extractOperations() to extract resource
  from displayOptions.show.resource
- Bump version to 2.42.1

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 18:18:19 +02:00
czlonkowski
7f7150b2f3 fix: add resource grouping to community node operations and restore 584 community nodes
Community nodes copied from a pre-fix DB had flat operations without resource
grouping. Fixed by:

1. Updating community-node-service.ts extractOperations() to extract resource
   from displayOptions.show.resource (same fix as property-extractor.ts)
2. Re-extracting operations from properties_schema for all 1,396 nodes
3. Restoring 584 community nodes from the n8n 2.13.3 DB snapshot
4. Rebuilding FTS5 index

Result: 366 community nodes now have resource-grouped operations (up from 10).
64 community nodes remain flat (they have no resource/operation pattern).

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:46:22 +02:00
Romuald Członkowski
89a9e5ed1c Merge pull request #679 from czlonkowski/feat/search-operations-and-workflow-patterns 2026-03-30 16:54:55 +02:00
czlonkowski
bda2009b77 feat: add includeOperations to search_nodes and patterns mode to search_templates
- Add `includeOperations` flag to search_nodes that returns resource/operation
  trees per result (e.g., Slack: 7 resources, 44 operations). Saves a get_node
  round-trip when building workflows.
- Add `searchMode: "patterns"` to search_templates — lightweight workflow pattern
  summaries mined from 2,700+ templates (node frequency, co-occurrence, connection
  chains across 10 task categories).
- Fix operations extraction: use filter() instead of find() to capture ALL
  operation properties, each mapped to its resource via displayOptions.
- Fix FTS-to-LIKE fallback silently dropping search options.
- Add mine-workflow-patterns.ts script (npm run mine:patterns).
- Restore 584 community nodes in database after rebuild.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:45:03 +02:00
Romuald Członkowski
20ebfbb0fc fix: validation bugs — If/Switch version check, Set false positive, bare expressions (#675, #676, #677) (#678)
- #675: Wire `validateConditionNodeStructure` into `WorkflowValidator` with
  version-conditional checks (If v2.2+ requires options, v2.0-2.1 validates
  operators, v1.x skipped; Switch v3.2+ requires options)
- #676: Fix `validateSet` to check `assignments.assignments` (v3+) alongside
  `config.values` (v1/v2), eliminating false positive warnings
- #677: Add anchored heuristic pre-pass in `ExpressionValidator` detecting bare
  `$json`, `$node`, `$input`, `$execution`, `$workflow`, `$prevNode`, `$env`,
  `$now`, `$today`, `$itemIndex`, `$runIndex` references missing `={{ }}`

25 new tests across 3 test files.

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

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:29:04 +02:00
Romuald Członkowski
6e4a9d520d fix: raise session timeout default, fix VS Code MCP compatibility (#674)
* fix: raise session timeout default and fix VS Code MCP compatibility (#626, #600, #611)

- #626: Raise SESSION_TIMEOUT_MINUTES default from 5 to 30 minutes.
  Complex editing sessions easily exceed 5 min between LLM calls.

- #600: Add z.preprocess(tryParseJson, ...) to operations parameter
  in n8n_update_partial_workflow. VS Code extension sends arrays as
  JSON strings.

- #611: Strip undefined values from tool args via JSON round-trip
  before Zod validation. VS Code sends explicit undefined which
  Zod's .optional() rejects.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: deduplicate tryParseJson — export from handlers-n8n-manager

tryParseJson was duplicated in handlers-workflow-diff.ts. Now imported
from handlers-n8n-manager.ts where it was already defined. Updated
test mock to use importOriginal so the real function is available.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:56:30 +01:00
Romuald Członkowski
fb2d306dc3 fix: intercept stdout writes to prevent JSON-RPC corruption in stdio mode (#673)
* fix: intercept process.stdout.write to prevent JSON-RPC corruption in stdio mode (#628, #627, #567)

Console method suppression alone was insufficient — native modules, n8n packages,
and third-party code can call process.stdout.write() directly, leaking debug output
(refCount, dbPath, clientVersion, protocolVersion, etc.) into the MCP JSON-RPC stream.

Added stdout write interceptor that only allows JSON-RPC messages through (objects
containing "jsonrpc" field). All other writes are redirected to stderr. This fixes
the flood of "Unexpected token is not valid JSON" warnings on every new Claude
Desktop chat.

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: add Docker Hub login to fix buildx bootstrap rate limiting

GitHub-hosted runners hit Docker Hub anonymous pull limits when
setup-buildx-action pulls moby/buildkit. Add docker/login-action
for Docker Hub before setup-buildx-action in all 4 workflows:
docker-build.yml, docker-build-fast.yml, docker-build-n8n.yml, release.yml.

Uses DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:26:43 +01:00
110 changed files with 6240 additions and 1437 deletions

View File

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

View File

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

View File

@@ -71,24 +71,30 @@ jobs:
" "
echo "✅ Synced package.runtime.json to version $VERSION" echo "✅ Synced package.runtime.json to version $VERSION"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata - name: Extract metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: | tags: |
@@ -101,7 +107,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}} type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v7
with: with:
context: . context: .
no-cache: false no-cache: false
@@ -173,16 +179,22 @@ jobs:
" "
echo "✅ Synced package.runtime.json to version $VERSION" echo "✅ Synced package.runtime.json to version $VERSION"
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry - name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
@@ -190,7 +202,7 @@ jobs:
- name: Extract metadata for Railway - name: Extract metadata for Railway
id: meta-railway id: meta-railway
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-railway
tags: | tags: |
@@ -203,7 +215,7 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}} type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Railway Docker image - name: Build and push Railway Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v7
with: with:
context: . context: .
file: ./Dockerfile.railway file: ./Dockerfile.railway

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,148 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [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
- **`workflow-patterns.json` missing from npm package** (Issue #681): Added `data/workflow-patterns.json` to the `files` array in `package.json` so the patterns file is included in the published npm package and works out of the box without manual generation.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.42.1] - 2026-03-30
### Fixed
- **Community nodes missing from database after rebuild**: Restored 584 community nodes from the n8n 2.13.3 snapshot and re-extracted operations with resource grouping from `properties_schema`. 366 community nodes now have proper resource-grouped operations.
- **Community node service missing resource extraction**: `extractOperations()` in `community-node-service.ts` was not extracting `resource` from `displayOptions.show.resource`, same issue that was fixed in `property-extractor.ts` in v2.42.0.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.42.0] - 2026-03-30
### Added
- **`includeOperations` flag for search_nodes**: Opt-in parameter that returns a resource/operation tree per search result, grouped by resource (e.g., Slack returns 7 resources with 44 operations). Saves a mandatory `get_node` round-trip when building workflows. Adds ~100-300 tokens per result.
- **`searchMode: "patterns"` for search_templates**: New lightweight mode that serves workflow pattern summaries mined from 2,700+ templates. Returns common node combinations, connection chains, and frequency data per task category (10 categories: ai_automation, webhook_processing, scheduling, etc.). Use `task` parameter for category-specific patterns or omit for overview.
- **Workflow pattern mining script** (`npm run mine:patterns`): Extracts node frequency, co-occurrence, and connection topology from the template database. Two-pass pipeline: Pass 1 analyzes `nodes_used` metadata (no decompression), Pass 2 decompresses workflows for connection analysis. Produces `data/workflow-patterns.json` with 554 node types, 3,201 edges, and 5,246 chains.
### Fixed
- **Operations extraction now includes resource grouping**: The property extractor was using `find()` to get only the first `operation` property, but n8n nodes have multiple operation properties each mapped to a different resource via `displayOptions.show.resource`. Changed to `filter()` to capture all operation properties. Slack went from 17 flat operations to 44 operations across 7 named resources.
- **FTS-to-LIKE fallback dropped search options**: When the FTS5 search fell back to LIKE-based search (e.g., for "http request"), the `options` object (including `includeOperations`, `includeExamples`, `source`) was silently lost. Now correctly passed through.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.4] - 2026-03-30
### Fixed
- **`validate_workflow` misses `conditions.options` check for If/Switch nodes** (Issue #675): Added version-conditional validation — If v2.2+ and Switch v3.2+ now require `conditions.options` metadata, If v2.0-2.1 validates operator structures, and v1.x is left unchecked. Previously only caught by `n8n_create_workflow` pre-flight but not by offline `validate_workflow`.
- **False positive "Set node has no fields configured" for Set v3+** (Issue #676): The `validateSet` checker now recognizes `config.assignments.assignments` (v3+ schema) in addition to `config.values` (v1/v2 schema). Updated suggestion text to match current UI terminology.
- **Expression validator does not detect unwrapped n8n expressions** (Issue #677): Added heuristic pre-pass that detects bare `$json`, `$node`, `$input`, `$execution`, `$workflow`, `$prevNode`, `$env`, `$now`, `$today`, `$itemIndex`, and `$runIndex` references missing `={{ }}` wrappers. Uses anchored patterns to avoid false positives. Emits warnings, not errors.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.3] - 2026-03-27
### Fixed
- **Session timeout default too low** (Issue #626): Raised `SESSION_TIMEOUT_MINUTES` default from 5 to 30 minutes. The 5-minute default caused sessions to expire mid-operation during complex multi-step workflows (validate → get structure → patch → validate), forcing users to retry. Configurable via environment variable.
- **Operations array received as string from VS Code** (Issue #600): Added `z.preprocess` JSON string parsing to the `operations` parameter in `n8n_update_partial_workflow`. The VS Code MCP extension serializes arrays as JSON strings — the Zod schema now transparently parses them before validation.
- **`undefined` values rejected in MCP tool calls from VS Code** (Issue #611): Strip explicit `undefined` values from tool arguments before Zod validation. VS Code sends `undefined` as a value which Zod's `.optional()` rejects (it expects the field to be missing, not present-but-undefined).
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.2] - 2026-03-27
### Fixed
- **MCP initialization floods Claude Desktop with JSON parse errors** (Issues #628, #627, #567): Intercept `process.stdout.write` in stdio mode to redirect non-JSON-RPC output to stderr. Console method suppression alone was insufficient — native modules (better-sqlite3), n8n packages, and third-party code can call `process.stdout.write()` directly, corrupting the JSON-RPC stream. Only writes containing valid JSON-RPC messages (`{"jsonrpc":...}`) are now allowed through stdout; everything else is redirected to stderr. This fixes the flood of "Unexpected token is not valid JSON" warnings on every new chat in Claude Desktop, including leaked `refCount`, `dbPath`, `clientVersion`, `protocolVersion`, and other debug strings.
Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en
## [2.41.1] - 2026-03-27 ## [2.41.1] - 2026-03-27
### Fixed ### 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) [![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) [![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) [![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) [![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) [![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)

Binary file not shown.

2670
data/workflow-patterns.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,10 @@
import express from 'express'; import express from 'express';
import { InstanceContext } from './types/instance-context'; import { InstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state'; import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
export interface SingleSessionHTTPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export declare class SingleSessionHTTPServer { export declare class SingleSessionHTTPServer {
private transports; private transports;
private servers; private servers;
@@ -14,7 +18,8 @@ export declare class SingleSessionHTTPServer {
private sessionTimeout; private sessionTimeout;
private authToken; private authToken;
private cleanupTimer; private cleanupTimer;
constructor(); private generateWorkflowHandler?;
constructor(options?: SingleSessionHTTPServerOptions);
private startSessionCleanup; private startSessionCleanup;
private cleanupExpiredSessions; private cleanupExpiredSessions;
private removeSession; private removeSession;

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;AAwEpE,MAAM,WAAW,8BAA8B;IAC7C,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAED,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;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;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;YAsRF,eAAe;IA8D7B,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"}

View File

@@ -45,7 +45,7 @@ function logSecurityEvent(event, details) {
logger_1.logger.info(`[SECURITY] ${event}`, logEntry); logger_1.logger.info(`[SECURITY] ${event}`, logEntry);
} }
class SingleSessionHTTPServer { class SingleSessionHTTPServer {
constructor() { constructor(options) {
this.transports = {}; this.transports = {};
this.servers = {}; this.servers = {};
this.sessionMetadata = {}; this.sessionMetadata = {};
@@ -53,9 +53,10 @@ class SingleSessionHTTPServer {
this.contextSwitchLocks = new Map(); this.contextSwitchLocks = new Map();
this.session = null; this.session = null;
this.consoleManager = new console_manager_1.ConsoleManager(); this.consoleManager = new console_manager_1.ConsoleManager();
this.sessionTimeout = parseInt(process.env.SESSION_TIMEOUT_MINUTES || '5', 10) * 60 * 1000; this.sessionTimeout = parseInt(process.env.SESSION_TIMEOUT_MINUTES || '30', 10) * 60 * 1000;
this.authToken = null; this.authToken = null;
this.cleanupTimer = null; this.cleanupTimer = null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
this.validateEnvironment(); this.validateEnvironment();
this.startSessionCleanup(); this.startSessionCleanup();
} }
@@ -340,7 +341,9 @@ class SingleSessionHTTPServer {
else { else {
sessionIdToUse = sessionId || (0, uuid_1.v4)(); sessionIdToUse = sessionId || (0, uuid_1.v4)();
} }
const server = new server_1.N8NDocumentationMCPServer(instanceContext); const server = new server_1.N8NDocumentationMCPServer(instanceContext, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({ transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => sessionIdToUse, sessionIdGenerator: () => sessionIdToUse,
onsessioninitialized: (initializedSessionId) => { onsessioninitialized: (initializedSessionId) => {
@@ -504,7 +507,9 @@ class SingleSessionHTTPServer {
} }
try { try {
logger_1.logger.info('Creating new N8NDocumentationMCPServer for SSE...'); logger_1.logger.info('Creating new N8NDocumentationMCPServer for SSE...');
const server = new server_1.N8NDocumentationMCPServer(); const server = new server_1.N8NDocumentationMCPServer(undefined, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
const sessionId = (0, uuid_1.v4)(); const sessionId = (0, uuid_1.v4)();
logger_1.logger.info('Creating SSEServerTransport...'); logger_1.logger.info('Creating SSEServerTransport...');
const transport = new sse_js_1.SSEServerTransport('/mcp', res); const transport = new sse_js_1.SSEServerTransport('/mcp', res);

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

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

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"); const logger_1 = require("./utils/logger");
class N8NMCPEngine { class N8NMCPEngine {
constructor(options = {}) { constructor(options = {}) {
this.server = new http_server_single_session_1.SingleSessionHTTPServer(); this.server = new http_server_single_session_1.SingleSessionHTTPServer({
generateWorkflowHandler: options.generateWorkflowHandler,
});
this.startTime = new Date(); this.startTime = new Date();
if (options.logLevel) { if (options.logLevel) {
process.env.LOG_LEVEL = options.logLevel; process.env.LOG_LEVEL = options.logLevel;

View File

@@ -1 +1 @@
{"version":3,"file":"mcp-engine.js","sourceRoot":"","sources":["../src/mcp-engine.ts"],"names":[],"mappings":";;;AAQA,6EAAuE;AACvE,2CAAwC;AAqBxC,MAAa,YAAY;IAIvB,YAAY,UAAyB,EAAE;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,oDAAuB,EAAE,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAE5B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC;QAC3C,CAAC;IACH,CAAC;IAuBD,KAAK,CAAC,cAAc,CAClB,GAAY,EACZ,GAAa,EACb,eAAiC;QAEjC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,eAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAWD,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YACjD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAE1C,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;gBAClE,aAAa,EAAE,WAAW,CAAC,MAAM;gBACjC,WAAW,EAAE;oBACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;oBACpD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;oBACtD,IAAI,EAAE,IAAI;iBACX;gBACD,OAAO,EAAE,QAAQ;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,eAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC5C,OAAO;gBACL,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,CAAC;gBACT,aAAa,EAAE,KAAK;gBACpB,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;gBAC9C,OAAO,EAAE,QAAQ;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAMD,cAAc;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;IACtC,CAAC;IAkBD,kBAAkB;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,eAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;IAC1C,CAAC;IAkBD,mBAAmB,CAAC,QAAwB;QAC1C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,eAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAWD,KAAK,CAAC,QAAQ;QACZ,eAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAMD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;CACF;AAjKD,oCAiKC;AA2CD,kBAAe,YAAY,CAAC"} {"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 handleWorkflowVersions(args: unknown, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>; export declare function handleDeployTemplate(args: unknown, templateService: TemplateService, repository: NodeRepository, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleTriggerWebhookWorkflow(args: unknown, context?: InstanceContext): Promise<McpToolResponse>; export declare function handleTriggerWebhookWorkflow(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function tryParseJson(val: unknown): unknown;
export declare function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>; export declare function handleCreateTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>; export declare function handleListTables(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;
export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>; export declare function handleGetTable(args: unknown, context?: InstanceContext): Promise<McpToolResponse>;

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.handleWorkflowVersions = handleWorkflowVersions;
exports.handleDeployTemplate = handleDeployTemplate; exports.handleDeployTemplate = handleDeployTemplate;
exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow; exports.handleTriggerWebhookWorkflow = handleTriggerWebhookWorkflow;
exports.tryParseJson = tryParseJson;
exports.handleCreateTable = handleCreateTable; exports.handleCreateTable = handleCreateTable;
exports.handleListTables = handleListTables; exports.handleListTables = handleListTables;
exports.handleGetTable = handleGetTable; exports.handleGetTable = handleGetTable;

File diff suppressed because one or more lines are too long

View File

@@ -55,7 +55,7 @@ const NODE_TARGETING_OPERATIONS = new Set([
]); ]);
const workflowDiffSchema = zod_1.z.object({ const workflowDiffSchema = zod_1.z.object({
id: zod_1.z.string(), id: zod_1.z.string(),
operations: zod_1.z.array(zod_1.z.object({ operations: zod_1.z.preprocess(handlers_n8n_manager_1.tryParseJson, zod_1.z.array(zod_1.z.object({
type: zod_1.z.string(), type: zod_1.z.string(),
description: zod_1.z.string().optional(), description: zod_1.z.string().optional(),
node: zod_1.z.any().optional(), node: zod_1.z.any().optional(),
@@ -93,7 +93,7 @@ const workflowDiffSchema = zod_1.z.object({
} }
} }
return op; return op;
})), }))),
validateOnly: zod_1.z.boolean().optional(), validateOnly: zod_1.z.boolean().optional(),
continueOnError: zod_1.z.boolean().optional(), continueOnError: zod_1.z.boolean().optional(),
createBackup: zod_1.z.boolean().optional(), createBackup: zod_1.z.boolean().optional(),

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

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":"AA0CA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAA2B,MAAM,4BAA4B,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAmGnE,UAAU,gBAAgB;IACxB,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;CACnD;AAED,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;IACpC,OAAO,CAAC,uBAAuB,CAAC,CAA0B;gBAE9C,eAAe,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,gBAAgB;IA+GnG,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;IAiYrB,OAAO,CAAC,wBAAwB;IAoFhC,OAAO,CAAC,kBAAkB;IA0E1B,OAAO,CAAC,uBAAuB;IAwB/B,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,2BAA2B;YAgZrB,SAAS;YA2DT,WAAW;YAkFX,WAAW;YA2CX,cAAc;YAuNd,gBAAgB;IAuE9B,OAAO,CAAC,mBAAmB;IAwE3B,OAAO,CAAC,eAAe;YAsBT,eAAe;IA4M7B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,uBAAuB;IA0D/B,OAAO,CAAC,iBAAiB;YAqFX,WAAW;YAgCX,oBAAoB;IAuFlC,OAAO,CAAC,aAAa;YAQP,qBAAqB;IA4DnC,OAAO,CAAC,mBAAmB;YAyCb,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;IAqB7B,OAAO,CAAC,qBAAqB,CASb;IAEhB,OAAO,CAAC,mBAAmB;YAsDb,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"}

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 telemetry_1 = require("../telemetry");
const startup_checkpoints_1 = require("../telemetry/startup-checkpoints"); const startup_checkpoints_1 = require("../telemetry/startup-checkpoints");
class N8NDocumentationMCPServer { class N8NDocumentationMCPServer {
constructor(instanceContext, earlyLogger) { constructor(instanceContext, earlyLogger, options) {
this.db = null; this.db = null;
this.repository = null; this.repository = null;
this.templateService = null; this.templateService = null;
@@ -86,8 +86,10 @@ class N8NDocumentationMCPServer {
this.sharedDbState = null; this.sharedDbState = null;
this.isShutdown = false; this.isShutdown = false;
this.dbHealthChecked = false; this.dbHealthChecked = false;
this.workflowPatternsCache = null;
this.instanceContext = instanceContext; this.instanceContext = instanceContext;
this.earlyLogger = earlyLogger || null; this.earlyLogger = earlyLogger || null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
const envDbPath = process.env.NODE_DB_PATH; const envDbPath = process.env.NODE_DB_PATH;
let dbPath = null; let dbPath = null;
let possiblePaths = []; let possiblePaths = [];
@@ -499,6 +501,9 @@ class N8NDocumentationMCPServer {
} }
} }
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs); processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
if (processedArgs) {
processedArgs = JSON.parse(JSON.stringify(processedArgs));
}
try { try {
logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs }); logger_1.logger.debug(`Executing tool: ${name}`, { args: processedArgs });
const startTime = Date.now(); const startTime = Date.now();
@@ -931,6 +936,7 @@ class N8NDocumentationMCPServer {
return this.searchNodes(args.query, limit, { return this.searchNodes(args.query, limit, {
mode: args.mode, mode: args.mode,
includeExamples: args.includeExamples, includeExamples: args.includeExamples,
includeOperations: args.includeOperations,
source: args.source source: args.source
}); });
case 'get_node': case 'get_node':
@@ -1022,6 +1028,8 @@ class N8NDocumentationMCPServer {
requiredService: args.requiredService, requiredService: args.requiredService,
targetAudience: args.targetAudience targetAudience: args.targetAudience
}, searchLimit, searchOffset); }, searchLimit, searchOffset);
case 'patterns':
return this.getWorkflowPatterns(args.task, searchLimit);
case 'keyword': case 'keyword':
default: default:
if (!args.query) { if (!args.query) {
@@ -1132,6 +1140,44 @@ class N8NDocumentationMCPServer {
throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`); throw new Error(`Unknown action: ${dtAction}. Valid actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows`);
} }
} }
case 'n8n_generate_workflow': {
this.validateToolParams(name, args, ['description']);
if (this.generateWorkflowHandler && this.instanceContext) {
await this.ensureInitialized();
if (!this.repository) {
throw new Error('Repository not initialized');
}
const repo = this.repository;
const ctx = this.instanceContext;
const helpers = {
createWorkflow: (wfArgs) => n8nHandlers.handleCreateWorkflow(wfArgs, ctx),
validateWorkflow: (id) => n8nHandlers.handleValidateWorkflow({ id }, repo, ctx),
autofixWorkflow: (id) => n8nHandlers.handleAutofixWorkflow({ id }, repo, ctx),
getWorkflow: (id) => n8nHandlers.handleGetWorkflow({ id }, ctx),
};
try {
const result = await this.generateWorkflowHandler(args, ctx, helpers);
return result ?? { success: false, error: 'Handler returned no result' };
}
catch (err) {
const message = err instanceof Error ? err.message : String(err);
return { success: false, error: message };
}
}
return {
hosted_only: true,
message: 'The n8n_generate_workflow tool is available exclusively on the hosted version of n8n-mcp. ' +
'It uses AI to generate complete, validated n8n workflows from natural language descriptions.\n\n' +
'To access this feature:\n' +
'1. Register for free at https://dashboard.n8n-mcp.com\n' +
'2. Connect your n8n instance\n' +
'3. Use your hosted API key in your MCP client\n\n' +
'The hosted service includes:\n' +
'- 73,000+ pre-built workflow templates with instant deployment\n' +
'- AI-powered fresh generation for custom workflows\n' +
'- Automatic validation and error correction'
};
}
default: default:
throw new Error(`Unknown tool: ${name}`); throw new Error(`Unknown tool: ${name}`);
} }
@@ -1270,7 +1316,7 @@ class N8NDocumentationMCPServer {
return { query, results: [], totalCount: 0 }; return { query, results: [], totalCount: 0 };
} }
if (mode === 'FUZZY') { if (mode === 'FUZZY') {
return this.searchNodesFuzzy(cleanedQuery, limit); return this.searchNodesFuzzy(cleanedQuery, limit, { includeOperations: options?.includeOperations });
} }
let ftsQuery; let ftsQuery;
if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) { if (cleanedQuery.startsWith('"') && cleanedQuery.endsWith('"')) {
@@ -1338,7 +1384,7 @@ class N8NDocumentationMCPServer {
const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest'); const hasHttpRequest = scoredNodes.some(n => n.node_type === 'nodes-base.httpRequest');
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) { if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
logger_1.logger.debug('FTS missed HTTP Request node, augmenting with LIKE search'); logger_1.logger.debug('FTS missed HTTP Request node, augmenting with LIKE search');
return this.searchNodesLIKE(query, limit); return this.searchNodesLIKE(query, limit, options);
} }
const result = { const result = {
query, query,
@@ -1362,6 +1408,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads; nodeResult.npmDownloads = node.npm_downloads;
} }
} }
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: scoredNodes.length totalCount: scoredNodes.length
@@ -1412,7 +1464,7 @@ class N8NDocumentationMCPServer {
return this.searchNodesLIKE(query, limit); return this.searchNodesLIKE(query, limit);
} }
} }
async searchNodesFuzzy(query, limit) { async searchNodesFuzzy(query, limit, options) {
if (!this.db) if (!this.db)
throw new Error('Database not initialized'); throw new Error('Database not initialized');
const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0); const words = query.toLowerCase().split(/\s+/).filter(w => w.length > 0);
@@ -1440,14 +1492,23 @@ class N8NDocumentationMCPServer {
return { return {
query, query,
mode: 'FUZZY', mode: 'FUZZY',
results: matchingNodes.map(node => ({ results: matchingNodes.map(node => {
nodeType: node.node_type, const nodeResult = {
workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type), nodeType: node.node_type,
displayName: node.display_name, workflowNodeType: (0, node_utils_1.getWorkflowNodeType)(node.package_name, node.node_type),
description: node.description, displayName: node.display_name,
category: node.category, description: node.description,
package: node.package_name category: node.category,
})), package: node.package_name
};
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult;
}),
totalCount: matchingNodes.length totalCount: matchingNodes.length
}; };
} }
@@ -1568,6 +1629,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads; nodeResult.npmDownloads = node.npm_downloads;
} }
} }
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: rankedNodes.length totalCount: rankedNodes.length
@@ -1635,6 +1702,12 @@ class N8NDocumentationMCPServer {
nodeResult.npmDownloads = node.npm_downloads; nodeResult.npmDownloads = node.npm_downloads;
} }
} }
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: rankedNodes.length totalCount: rankedNodes.length
@@ -1938,6 +2011,47 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
})), })),
}; };
} }
buildOperationsTree(operationsRaw) {
if (!operationsRaw)
return undefined;
let ops;
if (typeof operationsRaw === 'string') {
try {
ops = JSON.parse(operationsRaw);
}
catch {
return undefined;
}
}
else if (Array.isArray(operationsRaw)) {
ops = operationsRaw;
}
else {
return undefined;
}
if (!Array.isArray(ops) || ops.length === 0)
return undefined;
const byResource = new Map();
for (const op of ops) {
const resource = op.resource || 'default';
const opName = op.name || op.operation;
if (!opName)
continue;
if (!byResource.has(resource)) {
byResource.set(resource, []);
}
const list = byResource.get(resource);
if (!list.includes(opName)) {
list.push(opName);
}
}
if (byResource.size === 0)
return undefined;
return Array.from(byResource.entries()).map(([resource, operations]) => ({
resource,
operations
}));
}
async getNodeEssentials(nodeType, includeExamples) { async getNodeEssentials(nodeType, includeExamples) {
await this.ensureInitialized(); await this.ensureInitialized();
if (!this.repository) if (!this.repository)
@@ -2795,6 +2909,54 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
tip: `Found ${result.total} templates matching "${query}". Showing ${result.items.length}.` tip: `Found ${result.total} templates matching "${query}". Showing ${result.items.length}.`
}; };
} }
getWorkflowPatterns(category, limit = 10) {
if (!this.workflowPatternsCache) {
try {
const patternsPath = path_1.default.join(__dirname, '..', '..', 'data', 'workflow-patterns.json');
if ((0, fs_1.existsSync)(patternsPath)) {
this.workflowPatternsCache = JSON.parse((0, fs_1.readFileSync)(patternsPath, 'utf-8'));
}
else {
return { error: 'Workflow patterns not generated yet. Run: npm run mine:patterns' };
}
}
catch (e) {
return { error: `Failed to load workflow patterns: ${e instanceof Error ? e.message : String(e)}` };
}
}
const patterns = this.workflowPatternsCache;
if (category) {
const categoryData = patterns.categories[category];
if (!categoryData) {
const available = Object.keys(patterns.categories);
return { error: `Unknown category "${category}". Available: ${available.join(', ')}` };
}
const MAX_CHAINS = 5;
return {
category,
templateCount: categoryData.templateCount,
pattern: categoryData.pattern,
nodes: categoryData.nodes?.slice(0, limit).map(n => ({
type: n.type, freq: n.frequency, role: n.role
})),
chains: categoryData.commonChains?.slice(0, MAX_CHAINS).map(c => ({
path: c.chain.map(t => t.split('.').pop() ?? t), count: c.count, freq: c.frequency
})),
};
}
const overview = Object.entries(patterns.categories).map(([name, data]) => ({
category: name,
templateCount: data.templateCount,
pattern: data.pattern,
topNodes: data.nodes?.slice(0, 5).map(n => n.displayName || n.type),
}));
return {
templateCount: patterns.templateCount,
generatedAt: patterns.generatedAt,
categories: overview,
tip: 'Use search_templates({searchMode: "patterns", task: "category_name"}) for full pattern data with nodes, chains, and tips.',
};
}
async getTemplatesForTask(task, limit = 10, offset = 0) { async getTemplatesForTask(task, limit = 10, offset = 0) {
await this.ensureInitialized(); await this.ensureInitialized();
if (!this.templateService) if (!this.templateService)

File diff suppressed because one or more lines are too long

View File

@@ -29,6 +29,16 @@ console.table = () => { };
console.clear = () => { }; console.clear = () => { };
console.count = () => { }; console.count = () => { };
console.countReset = () => { }; console.countReset = () => { };
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
const stderrWrite = process.stderr.write.bind(process.stderr);
process.stdout.write = function (chunk, encodingOrCallback, callback) {
const str = typeof chunk === 'string' ? chunk : chunk.toString();
const trimmed = str.trimStart();
if (trimmed.startsWith('{') && trimmed.includes('"jsonrpc"')) {
return originalStdoutWrite(chunk, encodingOrCallback, callback);
}
return stderrWrite(chunk, encodingOrCallback, callback);
};
const server_1 = require("./server"); const server_1 = require("./server");
let server = null; let server = null;
async function main() { async function main() {

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', category: 'discovery',
essentials: { essentials: {
description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.', description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.',
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples'], keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples', 'includeOperations'],
example: 'search_nodes({query: "webhook"})', example: 'search_nodes({query: "webhook"})',
performance: '<20ms even for complex queries', performance: '<20ms even for complex queries',
tips: [ tips: [
@@ -15,7 +15,8 @@ exports.searchNodesDoc = {
'FUZZY mode: Handles typos and spelling errors', 'FUZZY mode: Handles typos and spelling errors',
'Use quotes for exact phrases: "google sheets"', 'Use quotes for exact phrases: "google sheets"',
'Use source="community" to search only community nodes', 'Use source="community" to search only community nodes',
'Use source="verified" for verified community nodes only' 'Use source="verified" for verified community nodes only',
'Use includeOperations=true to get resource/operation trees without a separate get_node call'
] ]
}, },
full: { full: {
@@ -25,20 +26,17 @@ exports.searchNodesDoc = {
limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false }, limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false },
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false }, mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false }, source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false } includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false },
includeOperations: { type: 'boolean', description: 'Include resource/operation tree per node. Default: false. Adds ~100-300 tokens per result but saves a get_node round-trip. Only returned for nodes with resource/operation patterns — trigger nodes and freeform nodes (Code, HTTP Request) omit this field.', required: false }
}, },
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.', returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
examples: [ examples: [
'search_nodes({query: "webhook"}) - Returns Webhook node as top result', 'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
'search_nodes({query: "database"}) - Returns MySQL, Postgres, MongoDB, Redis, etc.',
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words', 'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo', 'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
'search_nodes({query: "http api"}) - Finds HTTP Request, GraphQL, REST nodes',
'search_nodes({query: "transform data"}) - Finds Set, Code, Function, Item Lists nodes',
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes', 'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
'search_nodes({query: "pdf", source: "verified"}) - Find verified community PDF nodes', 'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples',
'search_nodes({query: "brightdata"}) - Find BrightData community node', 'search_nodes({query: "slack", includeOperations: true}) - Get Slack with resource/operation tree (7 resources, 44 ops)'
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples'
], ],
useCases: [ useCases: [
'Finding nodes when you know partial names', 'Finding nodes when you know partial names',

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_executions: workflow_management_1.n8nExecutionsDoc,
n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc, n8n_workflow_versions: workflow_management_1.n8nWorkflowVersionsDoc,
n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc, n8n_deploy_template: workflow_management_1.n8nDeployTemplateDoc,
n8n_manage_datatable: workflow_management_1.n8nManageDatatableDoc n8n_manage_datatable: workflow_management_1.n8nManageDatatableDoc,
n8n_generate_workflow: workflow_management_1.n8nGenerateWorkflowDoc
}; };
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

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', name: 'search_templates',
category: 'templates', category: 'templates',
essentials: { essentials: {
description: 'Unified template search with multiple modes: keyword search, by node types, by task type, or by metadata. 2,700+ templates available.', description: 'Unified template search with multiple modes: keyword search, by node types, by task type, by metadata, or patterns. 2,700+ templates available.',
keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'], keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'],
example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})', example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})',
performance: 'Fast (<100ms) - FTS5 full-text search', performance: 'Fast (<100ms) - FTS5 full-text search',
@@ -13,7 +13,9 @@ exports.searchTemplatesDoc = {
'searchMode="keyword" (default): Search by name/description', 'searchMode="keyword" (default): Search by name/description',
'searchMode="by_nodes": Find templates using specific nodes', 'searchMode="by_nodes": Find templates using specific nodes',
'searchMode="by_task": Get curated templates for common tasks', 'searchMode="by_task": Get curated templates for common tasks',
'searchMode="by_metadata": Filter by complexity, services, audience' 'searchMode="by_metadata": Filter by complexity, services, audience',
'searchMode="patterns": Workflow pattern summaries across 10 task categories',
'patterns without task: overview of all categories. patterns with task: node frequencies + connection chains'
] ]
}, },
full: { full: {
@@ -22,14 +24,15 @@ exports.searchTemplatesDoc = {
- by_nodes: Find templates that use specific node types - by_nodes: Find templates that use specific node types
- by_task: Get curated templates for predefined task categories - by_task: Get curated templates for predefined task categories
- by_metadata: Filter by complexity, setup time, required services, or target audience - by_metadata: Filter by complexity, setup time, required services, or target audience
- patterns: Lightweight workflow pattern summaries mined from 2,700+ templates
**Available Task Types (for searchMode="by_task"):** **Available Task Types (for searchMode="by_task" and "patterns"):**
ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`, ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`,
parameters: { parameters: {
searchMode: { searchMode: {
type: 'string', type: 'string',
required: false, required: false,
description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata"' description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata", "patterns"'
}, },
query: { query: {
type: 'string', type: 'string',
@@ -44,7 +47,7 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
task: { task: {
type: 'string', type: 'string',
required: false, required: false,
description: 'For searchMode=by_task: Task type (ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations)' description: 'For searchMode=by_task: Task type. For searchMode=patterns: optional category filter (omit for overview of all categories). Values: ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations'
}, },
complexity: { complexity: {
type: 'string', type: 'string',
@@ -92,38 +95,45 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
description: 'Pagination offset (default 0)' description: 'Pagination offset (default 0)'
} }
}, },
returns: `Returns an object containing: returns: `For keyword/by_nodes/by_task/by_metadata modes:
- templates: Array of matching templates - templates: Array of matching templates
- id: Template ID for get_template() - id: Template ID for get_template()
- name: Template name - name, description, author, nodes, views, created, url, metadata
- description: What the workflow does
- author: Creator information
- nodes: Array of node types used
- views: Popularity metric
- created: Creation date
- url: Link to template
- metadata: AI-generated metadata (complexity, services, etc.)
- totalFound: Total matching templates - totalFound: Total matching templates
- searchMode: The mode used`, - searchMode: The mode used
For patterns mode (no task):
- templateCount, generatedAt
- categories: Array of {category, templateCount, pattern, topNodes}
- tip: How to drill into a specific category
For patterns mode (with task):
- category, templateCount, pattern
- nodes: Array of {type, freq, role} (top nodes by frequency, limited by 'limit')
- chains: Array of {path, count, freq} (top 5 connection chains, short node names)`,
examples: [ examples: [
'// Keyword search (default)\nsearch_templates({query: "chatbot"})', '// Keyword search (default)\nsearch_templates({query: "chatbot"})',
'// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})', '// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})',
'// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})', '// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})',
'// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})', '// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})',
'// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})' '// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})',
'// Pattern overview — all categories with top nodes (~550 tokens)\nsearch_templates({searchMode: "patterns"})',
'// Detailed patterns for a category — node frequencies + connection chains\nsearch_templates({searchMode: "patterns", task: "ai_automation"})'
], ],
useCases: [ useCases: [
'Find workflows by business purpose (keyword search)', 'Find workflows by business purpose (keyword search)',
'Find templates using specific integrations (by_nodes)', 'Find templates using specific integrations (by_nodes)',
'Get pre-built solutions for common tasks (by_task)', 'Get pre-built solutions for common tasks (by_task)',
'Filter by complexity for team skill level (by_metadata)', 'Filter by complexity for team skill level (by_metadata)',
'Find templates requiring specific services (by_metadata)' 'Understand common workflow shapes before building (patterns)',
'Architecture planning — which nodes go together (patterns)'
], ],
performance: `Fast performance across all modes: performance: `Fast performance across all modes:
- keyword: <50ms with FTS5 indexing - keyword: <50ms with FTS5 indexing
- by_nodes: <100ms with indexed lookups - by_nodes: <100ms with indexed lookups
- by_task: <50ms from curated cache - by_task: <50ms from curated cache
- by_metadata: <100ms with filtered queries`, - by_metadata: <100ms with filtered queries
- patterns: <10ms (pre-mined, cached in memory)`,
bestPractices: [ bestPractices: [
'Use searchMode="by_task" for common automation patterns', 'Use searchMode="by_task" for common automation patterns',
'Use searchMode="by_nodes" when you know which integrations you need', 'Use searchMode="by_nodes" when you know which integrations you need',

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 { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
export { n8nDeployTemplateDoc } from './n8n-deploy-template'; export { n8nDeployTemplateDoc } from './n8n-deploy-template';
export { n8nManageDatatableDoc } from './n8n-manage-datatable'; export { n8nManageDatatableDoc } from './n8n-manage-datatable';
export { n8nGenerateWorkflowDoc } from './n8n-generate-workflow';
//# sourceMappingURL=index.d.ts.map //# sourceMappingURL=index.d.ts.map

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"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.n8nManageDatatableDoc = exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0; exports.n8nGenerateWorkflowDoc = exports.n8nManageDatatableDoc = exports.n8nDeployTemplateDoc = exports.n8nWorkflowVersionsDoc = exports.n8nExecutionsDoc = exports.n8nTestWorkflowDoc = exports.n8nAutofixWorkflowDoc = exports.n8nValidateWorkflowDoc = exports.n8nListWorkflowsDoc = exports.n8nDeleteWorkflowDoc = exports.n8nUpdatePartialWorkflowDoc = exports.n8nUpdateFullWorkflowDoc = exports.n8nGetWorkflowDoc = exports.n8nCreateWorkflowDoc = void 0;
var n8n_create_workflow_1 = require("./n8n-create-workflow"); var n8n_create_workflow_1 = require("./n8n-create-workflow");
Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } }); Object.defineProperty(exports, "n8nCreateWorkflowDoc", { enumerable: true, get: function () { return n8n_create_workflow_1.n8nCreateWorkflowDoc; } });
var n8n_get_workflow_1 = require("./n8n-get-workflow"); var n8n_get_workflow_1 = require("./n8n-get-workflow");
@@ -27,4 +27,6 @@ var n8n_deploy_template_1 = require("./n8n-deploy-template");
Object.defineProperty(exports, "n8nDeployTemplateDoc", { enumerable: true, get: function () { return n8n_deploy_template_1.n8nDeployTemplateDoc; } }); Object.defineProperty(exports, "n8nDeployTemplateDoc", { enumerable: true, get: function () { return n8n_deploy_template_1.n8nDeployTemplateDoc; } });
var n8n_manage_datatable_1 = require("./n8n-manage-datatable"); var n8n_manage_datatable_1 = require("./n8n-manage-datatable");
Object.defineProperty(exports, "n8nManageDatatableDoc", { enumerable: true, get: function () { return n8n_manage_datatable_1.n8nManageDatatableDoc; } }); Object.defineProperty(exports, "n8nManageDatatableDoc", { enumerable: true, get: function () { return n8n_manage_datatable_1.n8nManageDatatableDoc; } });
var n8n_generate_workflow_1 = require("./n8n-generate-workflow");
Object.defineProperty(exports, "n8nGenerateWorkflowDoc", { enumerable: true, get: function () { return n8n_generate_workflow_1.n8nGenerateWorkflowDoc; } });
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

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

View File

@@ -1 +1 @@
{"version":3,"file":"tools-documentation.js","sourceRoot":"","sources":["../../src/mcp/tools-documentation.ts"],"names":[],"mappings":";;AAEA,oDA+DC;AAED,4CAsHC;AAED,0DAWC;AAED,gDAIC;AAED,4CAMC;AApND,2CAAiD;AAEjD,SAAgB,oBAAoB,CAAC,QAAgB,EAAE,QAA+B,YAAY;IAEhG,IAAI,QAAQ,KAAK,4BAA4B,EAAE,CAAC;QAC9C,OAAO,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,IAAI,QAAQ,KAAK,wBAAwB,EAAE,CAAC;QAC1C,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,GAAG,8BAAkB,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,QAAQ,gEAAgE,CAAC;IAC3F,CAAC;IAED,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QAC5B,OAAO,KAAK,IAAI,CAAC,IAAI;;EAEvB,UAAU,CAAC,WAAW;;eAET,UAAU,CAAC,OAAO;;sBAEX,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;;mBAEtC,UAAU,CAAC,WAAW;;;EAGvC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;4DAES,QAAQ,oBAAoB,CAAC;IACvF,CAAC;IAGD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IACtB,OAAO,KAAK,IAAI,CAAC,IAAI;;EAErB,IAAI,CAAC,WAAW;;;EAGhB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CACtD,OAAO,KAAK,OAAO,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CACzF,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGV,IAAI,CAAC,OAAO;;;EAGZ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;EAGvE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG7C,IAAI,CAAC,WAAW;;;EAGhB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGlD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG3C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,SAAgB,gBAAgB,CAAC,QAA+B,YAAY;IAE1E,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClD,MAAM,mBAAmB,GAAG,WAAW,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC;IAE/F,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;gDAGqC,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDA0EV,CAAC;IACxD,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;IACtC,OAAO;;;gDAGuC,mBAAmB;;;;;;;;;;EAUjE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACrB,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAClF,OAAO,OAAO,YAAY;EAC1B,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YACrB,MAAM,IAAI,GAAG,8BAAkB,CAAC,QAAQ,CAAC,CAAC;YAC1C,OAAO,OAAO,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QAC7D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;yDAS0C,CAAC;AAC1D,CAAC;AAED,SAAgB,uBAAuB,CAAC,OAAe;IACrD,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,8BAAkB,CAAC,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,GAAG,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,CAAC;QACvG,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,kBAAkB,CAAC,QAAgB;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,8BAAkB,CAAC;SACtC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,SAAgB,gBAAgB;IAC9B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,CAAC,MAAM,CAAC,8BAAkB,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QAC/C,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC;AAGD,SAAS,0BAA0B,CAAC,QAA+B,YAAY;IAC7E,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0FAgC+E,CAAC;IACzF,CAAC;IAGD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA8KoC,CAAC;AAC9C,CAAC;AAED,SAAS,sBAAsB,CAAC,QAA+B,YAAY;IACzE,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;QAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sFAgC2E,CAAC;IACrF,CAAC;IAGD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAoO4C,CAAC;AACtD,CAAC"} {"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

@@ -635,5 +635,45 @@ exports.n8nManagementTools = [
openWorldHint: true, openWorldHint: true,
}, },
}, },
{
name: 'n8n_generate_workflow',
description: 'Generate an n8n workflow from a natural language description using AI. ' +
'Call with just a description to get workflow proposals. ' +
'Then call again with deploy_id to deploy a chosen proposal, ' +
'or set skip_cache=true to generate a fresh workflow. ' +
'Use confirm_deploy=true to deploy a previously generated workflow.',
inputSchema: {
type: 'object',
properties: {
description: {
type: 'string',
description: 'Clear description of what the workflow should do. Include: trigger type ' +
'(webhook, schedule, manual), services to integrate (Slack, Gmail, etc.), and the logic/flow.'
},
skip_cache: {
type: 'boolean',
description: 'Set to true to skip proposals and generate a fresh workflow from scratch. ' +
'Returns a preview — call again with confirm_deploy=true to deploy it.'
},
deploy_id: {
type: 'string',
description: 'ID of a proposal to deploy. Get proposal IDs from a previous call ' +
'that returned status "proposals".'
},
confirm_deploy: {
type: 'boolean',
description: 'Set to true to deploy the workflow from the last generation preview.'
}
},
required: ['description'],
},
annotations: {
title: 'Generate Workflow',
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: true,
},
},
]; ];
//# sourceMappingURL=tools-n8n-manager.js.map //# sourceMappingURL=tools-n8n-manager.js.map

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)', description: 'Include top 2 real-world configuration examples from popular templates (default: false)',
default: false, default: false,
}, },
includeOperations: {
type: 'boolean',
default: false,
description: 'Include resource/operation tree per node. Adds ~100-300 tokens per result but saves a get_node round-trip.',
},
source: { source: {
type: 'string', type: 'string',
enum: ['all', 'core', 'community', 'verified'], enum: ['all', 'core', 'community', 'verified'],
@@ -237,14 +242,14 @@ exports.n8nDocumentationToolsFinal = [
}, },
{ {
name: 'search_templates', name: 'search_templates',
description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services.`, description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services, 'patterns' for lightweight workflow pattern summaries mined from 2700+ templates.`,
inputSchema: { inputSchema: {
type: 'object', type: 'object',
properties: { properties: {
searchMode: { searchMode: {
type: 'string', type: 'string',
enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata'], enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata', 'patterns'],
description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services', description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services, patterns=lightweight workflow pattern summaries',
default: 'keyword', default: 'keyword',
}, },
query: { query: {
@@ -278,7 +283,7 @@ exports.n8nDocumentationToolsFinal = [
'api_integration', 'api_integration',
'database_operations' 'database_operations'
], ],
description: 'For searchMode=by_task: the type of task', description: 'For searchMode=by_task: the type of task. For searchMode=patterns: optional category filter (omit for overview of all categories).',
}, },
category: { category: {
type: 'string', type: 'string',

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)) { if (description.properties && Array.isArray(description.properties)) {
const operationProp = description.properties.find((p) => p.name === 'operation' || p.name === 'action'); const operationProps = description.properties.filter((p) => p.name === 'operation' || p.name === 'action');
if (operationProp?.options) { for (const operationProp of operationProps) {
if (!operationProp?.options)
continue;
const resource = operationProp.displayOptions?.show?.resource?.[0];
operationProp.options.forEach((op) => { operationProp.options.forEach((op) => {
operations.push({ operations.push({
operation: op.value, operation: op.value,
name: op.name, name: op.name,
description: op.description description: op.description,
...(resource ? { resource } : {})
}); });
}); });
} }

File diff suppressed because one or more lines are too long

View File

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

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

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

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.cleanWorkflowForUpdate = cleanWorkflowForUpdate;
exports.validateWorkflowStructure = validateWorkflowStructure; exports.validateWorkflowStructure = validateWorkflowStructure;
exports.hasWebhookTrigger = hasWebhookTrigger; exports.hasWebhookTrigger = hasWebhookTrigger;
exports.validateConditionNodeStructure = validateConditionNodeStructure;
exports.validateFilterBasedNodeMetadata = validateFilterBasedNodeMetadata; exports.validateFilterBasedNodeMetadata = validateFilterBasedNodeMetadata;
exports.validateOperatorStructure = validateOperatorStructure; exports.validateOperatorStructure = validateOperatorStructure;
exports.getWebhookUrl = getWebhookUrl; exports.getWebhookUrl = getWebhookUrl;
@@ -229,7 +230,7 @@ function validateWorkflowStructure(workflow) {
} }
if (workflow.nodes) { if (workflow.nodes) {
workflow.nodes.forEach((node, index) => { workflow.nodes.forEach((node, index) => {
const filterErrors = validateFilterBasedNodeMetadata(node); const filterErrors = validateConditionNodeStructure(node);
if (filterErrors.length > 0) { if (filterErrors.length > 0) {
errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`)); errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`));
} }
@@ -332,73 +333,66 @@ function hasWebhookTrigger(workflow) {
return workflow.nodes.some(node => node.type === 'n8n-nodes-base.webhook' || return workflow.nodes.some(node => node.type === 'n8n-nodes-base.webhook' ||
node.type === 'n8n-nodes-base.webhookTrigger'); node.type === 'n8n-nodes-base.webhookTrigger');
} }
function validateFilterBasedNodeMetadata(node) { function validateConditionNodeStructure(node) {
const errors = []; const errors = [];
const isIFNode = node.type === 'n8n-nodes-base.if' && node.typeVersion >= 2.2; const typeVersion = node.typeVersion || 1;
const isSwitchNode = node.type === 'n8n-nodes-base.switch' && node.typeVersion >= 3.2; if (node.type === 'n8n-nodes-base.if') {
if (!isIFNode && !isSwitchNode) { if (typeVersion >= 2.2) {
return errors; errors.push(...validateFilterOptionsRequired(node.parameters?.conditions, 'conditions'));
} errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
if (isIFNode) {
const conditions = node.parameters.conditions;
if (!conditions?.options) {
errors.push('Missing required "conditions.options". ' +
'IF v2.2+ requires: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
} }
else { else if (typeVersion >= 2) {
const requiredFields = { errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
version: 2, }
leftValue: '', }
caseSensitive: 'boolean', else if (node.type === 'n8n-nodes-base.switch') {
typeValidation: 'strict' if (typeVersion >= 3.2) {
}; const rules = node.parameters?.rules;
for (const [field, expectedValue] of Object.entries(requiredFields)) { if (rules?.rules && Array.isArray(rules.rules)) {
if (!(field in conditions.options)) { rules.rules.forEach((rule, i) => {
errors.push(`Missing required field "conditions.options.${field}". ` + errors.push(...validateFilterOptionsRequired(rule.conditions, `rules.rules[${i}].conditions`));
`Expected value: ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue}`); errors.push(...validateFilterConditionOperators(rule.conditions, `rules.rules[${i}].conditions`));
} });
} }
} }
if (conditions?.conditions && Array.isArray(conditions.conditions)) {
conditions.conditions.forEach((condition, i) => {
const operatorErrors = validateOperatorStructure(condition.operator, `conditions.conditions[${i}].operator`);
errors.push(...operatorErrors);
});
}
}
if (isSwitchNode) {
const rules = node.parameters.rules;
if (rules?.rules && Array.isArray(rules.rules)) {
rules.rules.forEach((rule, ruleIndex) => {
if (!rule.conditions?.options) {
errors.push(`Missing required "rules.rules[${ruleIndex}].conditions.options". ` +
'Switch v3.2+ requires: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
}
else {
const requiredFields = {
version: 2,
leftValue: '',
caseSensitive: 'boolean',
typeValidation: 'strict'
};
for (const [field, expectedValue] of Object.entries(requiredFields)) {
if (!(field in rule.conditions.options)) {
errors.push(`Missing required field "rules.rules[${ruleIndex}].conditions.options.${field}". ` +
`Expected value: ${typeof expectedValue === 'string' ? `"${expectedValue}"` : expectedValue}`);
}
}
}
if (rule.conditions?.conditions && Array.isArray(rule.conditions.conditions)) {
rule.conditions.conditions.forEach((condition, condIndex) => {
const operatorErrors = validateOperatorStructure(condition.operator, `rules.rules[${ruleIndex}].conditions.conditions[${condIndex}].operator`);
errors.push(...operatorErrors);
});
}
});
}
} }
return errors; return errors;
} }
function validateFilterOptionsRequired(conditions, path) {
const errors = [];
if (!conditions || typeof conditions !== 'object')
return errors;
if (!conditions.options) {
errors.push(`Missing required "${path}.options". ` +
'Filter-based nodes require: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}');
}
else {
const requiredFields = [
['version', '2'],
['leftValue', '""'],
['caseSensitive', 'true'],
['typeValidation', '"strict"'],
];
for (const [field, display] of requiredFields) {
if (!(field in conditions.options)) {
errors.push(`Missing required field "${path}.options.${field}". Expected value: ${display}`);
}
}
}
return errors;
}
function validateFilterConditionOperators(conditions, path) {
const errors = [];
if (!conditions?.conditions || !Array.isArray(conditions.conditions))
return errors;
conditions.conditions.forEach((condition, i) => {
errors.push(...validateOperatorStructure(condition.operator, `${path}.conditions[${i}].operator`));
});
return errors;
}
function validateFilterBasedNodeMetadata(node) {
return validateConditionNodeStructure(node);
}
function validateOperatorStructure(operator, path) { function validateOperatorStructure(operator, path) {
const errors = []; const errors = [];
if (!operator || typeof operator !== 'object') { if (!operator || typeof operator !== 'object') {

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') { if (config.mode === 'manual') {
const hasFields = config.values && Object.keys(config.values).length > 0; const hasFieldsViaValues = config.values && Object.keys(config.values).length > 0;
const hasFieldsViaAssignments = config.assignments?.assignments
&& Array.isArray(config.assignments.assignments)
&& config.assignments.assignments.length > 0;
const hasFields = hasFieldsViaValues || hasFieldsViaAssignments;
if (!hasFields && !config.jsonOutput) { if (!hasFields && !config.jsonOutput) {
warnings.push({ warnings.push({
type: 'missing_common', type: 'missing_common',
message: 'Set node has no fields configured - will output empty items', message: 'Set node has no fields configured - will output empty items',
suggestion: 'Add fields in the Values section or use JSON mode' suggestion: 'Add field assignments or use JSON mode'
}); });
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"workflow-validator.d.ts","sourceRoot":"","sources":["../../src/services/workflow-validator.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAiBtE,eAAO,MAAM,sBAAsB,aASjC,CAAC;AAEH,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC;IAChB,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,uBAAuB,GAAG,qBAAqB,GAAG,cAAc,CAAC;IAC3E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,kBAAkB;IAC1B,CAAC,UAAU,EAAE,MAAM,GAAG;QACpB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC,CAAC;KACnF,CAAC;CACH;AAED,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,UAAU,EAAE;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,aAAa;IALvB,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,iBAAiB,CAAwB;gBAGvC,cAAc,EAAE,cAAc,EAC9B,aAAa,EAAE,OAAO,uBAAuB;IAWjD,gBAAgB,CACpB,QAAQ,EAAE,YAAY,EACtB,OAAO,GAAE;QACP,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAC;KACvD,GACL,OAAO,CAAC,wBAAwB,CAAC;IAgHpC,OAAO,CAAC,yBAAyB;YAkInB,gBAAgB;IAmO9B,OAAO,CAAC,mBAAmB;IA4F3B,OAAO,CAAC,yBAAyB;IAuHjC,OAAO,CAAC,gCAAgC;IAoFxC,OAAO,CAAC,wBAAwB;IAsChC,OAAO,CAAC,oBAAoB;IAuE5B,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,oBAAoB;IA4B5B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,wBAAwB;IAmBhC,OAAO,CAAC,yBAAyB;IA8DjC,OAAO,CAAC,8BAA8B;IAmDtC,OAAO,CAAC,wBAAwB;IAuChC,OAAO,CAAC,iBAAiB;IAoCzB,OAAO,CAAC,2BAA2B;IA4EnC,OAAO,CAAC,QAAQ;IA4EhB,OAAO,CAAC,mBAAmB;IA4F3B,OAAO,CAAC,wBAAwB;IA2BhC,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,qBAAqB;IAgG7B,OAAO,CAAC,qBAAqB;IA8C7B,OAAO,CAAC,mBAAmB;IA4E3B,OAAO,CAAC,sBAAsB;IAyT9B,OAAO,CAAC,yBAAyB;IAqCjC,OAAO,CAAC,gCAAgC;IA8BxC,OAAO,CAAC,gCAAgC;IAsFxC,OAAO,CAAC,gBAAgB;IA4CxB,OAAO,CAAC,2BAA2B;CAmEpC"} {"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 ai_tool_validators_1 = require("./ai-tool-validators");
const node_type_utils_1 = require("../utils/node-type-utils"); const node_type_utils_1 = require("../utils/node-type-utils");
const node_classification_1 = require("../utils/node-classification"); const node_classification_1 = require("../utils/node-classification");
const n8n_validation_1 = require("./n8n-validation");
const tool_variant_generator_1 = require("./tool-variant-generator"); const tool_variant_generator_1 = require("./tool-variant-generator");
const logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' }); const logger = new logger_1.Logger({ prefix: '[WorkflowValidator]' });
exports.VALID_CONNECTION_TYPES = new Set([ exports.VALID_CONNECTION_TYPES = new Set([
@@ -367,6 +368,17 @@ class WorkflowValidator {
message: typeof warning === 'string' ? warning : warning.message || String(warning) message: typeof warning === 'string' ? warning : warning.message || String(warning)
}); });
}); });
if (node.type === 'n8n-nodes-base.if' || node.type === 'n8n-nodes-base.switch') {
const conditionErrors = (0, n8n_validation_1.validateConditionNodeStructure)(node);
for (const err of conditionErrors) {
result.errors.push({
type: 'error',
nodeId: node.id,
nodeName: node.name,
message: err
});
}
}
} }
catch (error) { catch (error) {
result.errors.push({ result.errors.push({

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 './type-structures';
export * from './instance-context'; export * from './instance-context';
export * from './session-state'; export * from './session-state';
export * from './generate-workflow';
export interface MCPServerConfig { export interface MCPServerConfig {
port: number; port: number;
host: string; host: string;

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("./type-structures"), exports);
__exportStar(require("./instance-context"), exports); __exportStar(require("./instance-context"), exports);
__exportStar(require("./session-state"), exports); __exportStar(require("./session-state"), exports);
__exportStar(require("./generate-workflow"), exports);
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

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

2281
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "n8n-mcp", "name": "n8n-mcp",
"version": "2.41.1", "version": "2.45.0",
"description": "Integration between n8n workflow automation and Model Context Protocol (MCP)", "description": "Integration between n8n workflow automation and Model Context Protocol (MCP)",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@@ -90,6 +90,7 @@
"test:docker:unit": "./scripts/test-docker-config.sh unit", "test:docker:unit": "./scripts/test-docker-config.sh unit",
"test:docker:integration": "./scripts/test-docker-config.sh integration", "test:docker:integration": "./scripts/test-docker-config.sh integration",
"test:docker:security": "./scripts/test-docker-config.sh security", "test:docker:security": "./scripts/test-docker-config.sh security",
"mine:patterns": "tsx src/scripts/mine-workflow-patterns.ts",
"sanitize:templates": "node dist/scripts/sanitize-templates.js", "sanitize:templates": "node dist/scripts/sanitize-templates.js",
"db:rebuild": "node dist/scripts/rebuild-database.js", "db:rebuild": "node dist/scripts/rebuild-database.js",
"db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"", "db:init": "node -e \"new (require('./dist/services/sqlite-storage-service').SQLiteStorageService)(); console.log('Database initialized')\"",
@@ -123,6 +124,7 @@
"dist/**/*", "dist/**/*",
"ui-apps/dist/**/*", "ui-apps/dist/**/*",
"data/nodes.db", "data/nodes.db",
"data/workflow-patterns.json",
".env.example", ".env.example",
"README.md", "README.md",
"LICENSE", "LICENSE",
@@ -138,27 +140,27 @@
"@vitest/coverage-v8": "^3.2.4", "@vitest/coverage-v8": "^3.2.4",
"@vitest/runner": "^3.2.4", "@vitest/runner": "^3.2.4",
"@vitest/ui": "^3.2.4", "@vitest/ui": "^3.2.4",
"axios": "^1.11.0", "axios": "^1.14.0",
"axios-mock-adapter": "^2.1.0", "axios-mock-adapter": "^2.1.0",
"fishery": "^2.3.1", "fishery": "^2.3.1",
"msw": "^2.10.4", "msw": "^2.10.4",
"nodemon": "^3.1.10", "nodemon": "^3.1.14",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vitest": "^3.2.4" "vitest": "^3.2.4"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "1.28.0", "@modelcontextprotocol/sdk": "1.28.0",
"@n8n/n8n-nodes-langchain": "^2.13.1", "@n8n/n8n-nodes-langchain": "^2.14.1",
"@supabase/supabase-js": "^2.57.4", "@supabase/supabase-js": "^2.57.4",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"express": "^5.1.0", "express": "^5.1.0",
"express-rate-limit": "^7.1.5", "express-rate-limit": "^7.1.5",
"form-data": "^4.0.5", "form-data": "^4.0.5",
"lru-cache": "^11.2.1", "lru-cache": "^11.2.1",
"n8n": "^2.13.3", "n8n": "^2.14.2",
"n8n-core": "^2.13.1", "n8n-core": "^2.14.1",
"n8n-workflow": "^2.13.1", "n8n-workflow": "^2.14.1",
"openai": "^4.77.0", "openai": "^4.77.0",
"sql.js": "^1.13.0", "sql.js": "^1.13.0",
"tslib": "^2.6.2", "tslib": "^2.6.2",

View File

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

View File

@@ -343,10 +343,17 @@ export class CommunityNodeService {
const operations: any[] = []; const operations: any[] = [];
// Check properties for resource/operation pattern // Check properties for resource/operation pattern
// Nodes can have multiple operation properties, each mapped to a resource via displayOptions
if (nodeDesc.properties) { if (nodeDesc.properties) {
for (const prop of nodeDesc.properties) { for (const prop of nodeDesc.properties) {
if (prop.name === 'operation' && prop.options) { if ((prop.name === 'operation' || prop.name === 'action') && prop.options) {
operations.push(...prop.options); const resource = prop.displayOptions?.show?.resource?.[0];
for (const op of prop.options) {
operations.push({
...op,
...(resource ? { resource } : {})
});
}
} }
} }
} }

View File

@@ -26,6 +26,7 @@ import {
} from './utils/protocol-version'; } from './utils/protocol-version';
import { InstanceContext, validateInstanceContext } from './types/instance-context'; import { InstanceContext, validateInstanceContext } from './types/instance-context';
import { SessionState } from './types/session-state'; import { SessionState } from './types/session-state';
import { GenerateWorkflowHandler } from './types/generate-workflow';
import { closeSharedDatabase } from './database/shared-database'; import { closeSharedDatabase } from './database/shared-database';
dotenv.config(); dotenv.config();
@@ -97,6 +98,10 @@ function logSecurityEvent(
logger.info(`[SECURITY] ${event}`, logEntry); logger.info(`[SECURITY] ${event}`, logEntry);
} }
export interface SingleSessionHTTPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export class SingleSessionHTTPServer { export class SingleSessionHTTPServer {
// Map to store transports by session ID (following SDK pattern) // Map to store transports by session ID (following SDK pattern)
private transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; private transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
@@ -107,16 +112,17 @@ export class SingleSessionHTTPServer {
private session: Session | null = null; // Keep for SSE compatibility private session: Session | null = null; // Keep for SSE compatibility
private consoleManager = new ConsoleManager(); private consoleManager = new ConsoleManager();
private expressServer: any; private expressServer: any;
// Session timeout reduced from 30 minutes to 5 minutes for faster cleanup // Session timeout — configurable via SESSION_TIMEOUT_MINUTES environment variable
// Configurable via SESSION_TIMEOUT_MINUTES environment variable // Default 30 minutes: balances memory cleanup with real editing sessions (#626)
// This prevents memory buildup from stale sessions
private sessionTimeout = parseInt( private sessionTimeout = parseInt(
process.env.SESSION_TIMEOUT_MINUTES || '5', 10 process.env.SESSION_TIMEOUT_MINUTES || '30', 10
) * 60 * 1000; ) * 60 * 1000;
private authToken: string | null = null; private authToken: string | null = null;
private cleanupTimer: NodeJS.Timeout | null = null; private cleanupTimer: NodeJS.Timeout | null = null;
private generateWorkflowHandler?: GenerateWorkflowHandler;
constructor() {
constructor(options?: SingleSessionHTTPServerOptions) {
this.generateWorkflowHandler = options?.generateWorkflowHandler;
// Validate environment on construction // Validate environment on construction
this.validateEnvironment(); this.validateEnvironment();
// No longer pre-create session - will be created per initialize request following SDK pattern // No longer pre-create session - will be created per initialize request following SDK pattern
@@ -566,8 +572,10 @@ export class SingleSessionHTTPServer {
sessionIdToUse = sessionId || uuidv4(); sessionIdToUse = sessionId || uuidv4();
} }
const server = new N8NDocumentationMCPServer(instanceContext); const server = new N8NDocumentationMCPServer(instanceContext, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
transport = new StreamableHTTPServerTransport({ transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => sessionIdToUse, sessionIdGenerator: () => sessionIdToUse,
onsessioninitialized: (initializedSessionId: string) => { onsessioninitialized: (initializedSessionId: string) => {
@@ -773,7 +781,9 @@ export class SingleSessionHTTPServer {
try { try {
// Create new session // Create new session
logger.info('Creating new N8NDocumentationMCPServer for SSE...'); logger.info('Creating new N8NDocumentationMCPServer for SSE...');
const server = new N8NDocumentationMCPServer(); const server = new N8NDocumentationMCPServer(undefined, undefined, {
generateWorkflowHandler: this.generateWorkflowHandler,
});
// Generate cryptographically secure session ID // Generate cryptographically secure session ID
const sessionId = uuidv4(); const sessionId = uuidv4();

View File

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

View File

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

View File

@@ -2731,7 +2731,7 @@ const updateTableSchema = tableIdSchema.extend({
// MCP transports may serialize JSON objects/arrays as strings. // MCP transports may serialize JSON objects/arrays as strings.
// Parse them back, but return the original value on failure so Zod reports a proper type error. // Parse them back, but return the original value on failure so Zod reports a proper type error.
function tryParseJson(val: unknown): unknown { export function tryParseJson(val: unknown): unknown {
if (typeof val !== 'string') return val; if (typeof val !== 'string') return val;
try { return JSON.parse(val); } catch { return val; } try { return JSON.parse(val); } catch { return val; }
} }

View File

@@ -7,7 +7,7 @@ import { z } from 'zod';
import { McpToolResponse } from '../types/n8n-api'; import { McpToolResponse } from '../types/n8n-api';
import { WorkflowDiffRequest, WorkflowDiffOperation, WorkflowDiffValidationError } from '../types/workflow-diff'; import { WorkflowDiffRequest, WorkflowDiffOperation, WorkflowDiffValidationError } from '../types/workflow-diff';
import { WorkflowDiffEngine } from '../services/workflow-diff-engine'; import { WorkflowDiffEngine } from '../services/workflow-diff-engine';
import { getN8nApiClient } from './handlers-n8n-manager'; import { getN8nApiClient, tryParseJson } from './handlers-n8n-manager';
import { N8nApiError, getUserFriendlyErrorMessage } from '../utils/n8n-errors'; import { N8nApiError, getUserFriendlyErrorMessage } from '../utils/n8n-errors';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
import { InstanceContext } from '../types/instance-context'; import { InstanceContext } from '../types/instance-context';
@@ -39,7 +39,7 @@ const NODE_TARGETING_OPERATIONS = new Set([
// Zod schema for the diff request // Zod schema for the diff request
const workflowDiffSchema = z.object({ const workflowDiffSchema = z.object({
id: z.string(), id: z.string(),
operations: z.array(z.object({ operations: z.preprocess(tryParseJson, z.array(z.object({
type: z.string(), type: z.string(),
description: z.string().optional(), description: z.string().optional(),
// Node operations // Node operations
@@ -87,7 +87,7 @@ const workflowDiffSchema = z.object({
} }
} }
return op; return op;
})), }))),
validateOnly: z.boolean().optional(), validateOnly: z.boolean().optional(),
continueOnError: z.boolean().optional(), continueOnError: z.boolean().optional(),
createBackup: z.boolean().optional(), createBackup: z.boolean().optional(),

View File

@@ -7,7 +7,7 @@ import {
ListResourcesRequestSchema, ListResourcesRequestSchema,
ReadResourceRequestSchema, ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js'; } from '@modelcontextprotocol/sdk/types.js';
import { existsSync, promises as fs } from 'fs'; import { existsSync, readFileSync, promises as fs } from 'fs';
import path from 'path'; import path from 'path';
import { n8nDocumentationToolsFinal } from './tools'; import { n8nDocumentationToolsFinal } from './tools';
import { UIAppRegistry } from './ui'; import { UIAppRegistry } from './ui';
@@ -41,6 +41,7 @@ import {
STANDARD_PROTOCOL_VERSION STANDARD_PROTOCOL_VERSION
} from '../utils/protocol-version'; } from '../utils/protocol-version';
import { InstanceContext } from '../types/instance-context'; import { InstanceContext } from '../types/instance-context';
import { GenerateWorkflowHandler, GenerateWorkflowHelpers } from '../types/generate-workflow';
import { telemetry } from '../telemetry'; import { telemetry } from '../telemetry';
import { EarlyErrorLogger } from '../telemetry/early-error-logger'; import { EarlyErrorLogger } from '../telemetry/early-error-logger';
import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints'; import { STARTUP_CHECKPOINTS } from '../telemetry/startup-checkpoints';
@@ -141,6 +142,10 @@ interface VersionComparisonInfo {
type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo; type NodeInfoResponse = NodeMinimalInfo | NodeStandardInfo | NodeFullInfo | VersionHistoryInfo | VersionComparisonInfo;
interface MCPServerOptions {
generateWorkflowHandler?: GenerateWorkflowHandler;
}
export class N8NDocumentationMCPServer { export class N8NDocumentationMCPServer {
private server: Server; private server: Server;
private db: DatabaseAdapter | null = null; private db: DatabaseAdapter | null = null;
@@ -157,10 +162,12 @@ export class N8NDocumentationMCPServer {
private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup private useSharedDatabase: boolean = false; // Track if using shared DB for cleanup
private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release private sharedDbState: SharedDatabaseState | null = null; // Reference to shared DB state for release
private isShutdown: boolean = false; // Prevent double-shutdown private isShutdown: boolean = false; // Prevent double-shutdown
private generateWorkflowHandler?: GenerateWorkflowHandler;
constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger) { constructor(instanceContext?: InstanceContext, earlyLogger?: EarlyErrorLogger, options?: MCPServerOptions) {
this.instanceContext = instanceContext; this.instanceContext = instanceContext;
this.earlyLogger = earlyLogger || null; this.earlyLogger = earlyLogger || null;
this.generateWorkflowHandler = options?.generateWorkflowHandler;
// Check for test environment first // Check for test environment first
const envDbPath = process.env.NODE_DB_PATH; const envDbPath = process.env.NODE_DB_PATH;
let dbPath: string | null = null; let dbPath: string | null = null;
@@ -748,6 +755,13 @@ export class N8NDocumentationMCPServer {
// tool's inputSchema as the source of truth. // tool's inputSchema as the source of truth.
processedArgs = this.coerceStringifiedJsonParams(name, processedArgs); processedArgs = this.coerceStringifiedJsonParams(name, processedArgs);
// Strip undefined values from args (#611) — VS Code extension sends
// explicit undefined values which Zod's .optional() rejects.
// Removing them makes Zod treat them as missing (which .optional() allows).
if (processedArgs) {
processedArgs = JSON.parse(JSON.stringify(processedArgs));
}
try { try {
logger.debug(`Executing tool: ${name}`, { args: processedArgs }); logger.debug(`Executing tool: ${name}`, { args: processedArgs });
const startTime = Date.now(); const startTime = Date.now();
@@ -1303,6 +1317,7 @@ export class N8NDocumentationMCPServer {
return this.searchNodes(args.query, limit, { return this.searchNodes(args.query, limit, {
mode: args.mode, mode: args.mode,
includeExamples: args.includeExamples, includeExamples: args.includeExamples,
includeOperations: args.includeOperations,
source: args.source source: args.source
}); });
case 'get_node': case 'get_node':
@@ -1407,6 +1422,8 @@ export class N8NDocumentationMCPServer {
requiredService: args.requiredService, requiredService: args.requiredService,
targetAudience: args.targetAudience targetAudience: args.targetAudience
}, searchLimit, searchOffset); }, searchLimit, searchOffset);
case 'patterns':
return this.getWorkflowPatterns(args.task as string | undefined, searchLimit);
case 'keyword': case 'keyword':
default: default:
if (!args.query) { if (!args.query) {
@@ -1521,6 +1538,53 @@ export class N8NDocumentationMCPServer {
} }
} }
case 'n8n_generate_workflow': {
this.validateToolParams(name, args, ['description']);
if (this.generateWorkflowHandler && this.instanceContext) {
await this.ensureInitialized();
if (!this.repository) {
throw new Error('Repository not initialized');
}
const repo = this.repository;
const ctx = this.instanceContext;
const helpers: GenerateWorkflowHelpers = {
createWorkflow: (wfArgs) =>
n8nHandlers.handleCreateWorkflow(wfArgs, ctx),
validateWorkflow: (id) =>
n8nHandlers.handleValidateWorkflow({ id }, repo, ctx),
autofixWorkflow: (id) =>
n8nHandlers.handleAutofixWorkflow({ id }, repo, ctx),
getWorkflow: (id) =>
n8nHandlers.handleGetWorkflow({ id }, ctx),
};
try {
const result = await this.generateWorkflowHandler(args, ctx, helpers);
return result ?? { success: false, error: 'Handler returned no result' };
} catch (err: any) {
const message = err instanceof Error ? err.message : String(err);
return { success: false, error: message };
}
}
// No handler and/or no instanceContext — self-hosted deployment
return {
hosted_only: true,
message: 'The n8n_generate_workflow tool is available exclusively on the hosted version of n8n-mcp. ' +
'It uses AI to generate complete, validated n8n workflows from natural language descriptions.\n\n' +
'To access this feature:\n' +
'1. Register for free at https://dashboard.n8n-mcp.com\n' +
'2. Connect your n8n instance\n' +
'3. Use your hosted API key in your MCP client\n\n' +
'The hosted service includes:\n' +
'- 73,000+ pre-built workflow templates with instant deployment\n' +
'- AI-powered fresh generation for custom workflows\n' +
'- Automatic validation and error correction'
};
}
default: default:
throw new Error(`Unknown tool: ${name}`); throw new Error(`Unknown tool: ${name}`);
} }
@@ -1674,6 +1738,7 @@ export class N8NDocumentationMCPServer {
mode?: 'OR' | 'AND' | 'FUZZY'; mode?: 'OR' | 'AND' | 'FUZZY';
includeSource?: boolean; includeSource?: boolean;
includeExamples?: boolean; includeExamples?: boolean;
includeOperations?: boolean;
source?: 'all' | 'core' | 'community' | 'verified'; source?: 'all' | 'core' | 'community' | 'verified';
} }
): Promise<any> { ): Promise<any> {
@@ -1716,6 +1781,7 @@ export class N8NDocumentationMCPServer {
options?: { options?: {
includeSource?: boolean; includeSource?: boolean;
includeExamples?: boolean; includeExamples?: boolean;
includeOperations?: boolean;
source?: 'all' | 'core' | 'community' | 'verified'; source?: 'all' | 'core' | 'community' | 'verified';
} }
): Promise<any> { ): Promise<any> {
@@ -1729,7 +1795,7 @@ export class N8NDocumentationMCPServer {
// For FUZZY mode, use LIKE search with typo patterns // For FUZZY mode, use LIKE search with typo patterns
if (mode === 'FUZZY') { if (mode === 'FUZZY') {
return this.searchNodesFuzzy(cleanedQuery, limit); return this.searchNodesFuzzy(cleanedQuery, limit, { includeOperations: options?.includeOperations });
} }
let ftsQuery: string; let ftsQuery: string;
@@ -1820,7 +1886,7 @@ export class N8NDocumentationMCPServer {
if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) { if (cleanedQuery.toLowerCase().includes('http') && !hasHttpRequest) {
// FTS missed HTTP Request, fall back to LIKE search // FTS missed HTTP Request, fall back to LIKE search
logger.debug('FTS missed HTTP Request node, augmenting with LIKE search'); logger.debug('FTS missed HTTP Request node, augmenting with LIKE search');
return this.searchNodesLIKE(query, limit); return this.searchNodesLIKE(query, limit, options);
} }
const result: any = { const result: any = {
@@ -1848,6 +1914,14 @@ export class N8NDocumentationMCPServer {
} }
} }
// Add operations tree if requested
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: scoredNodes.length totalCount: scoredNodes.length
@@ -1915,7 +1989,13 @@ export class N8NDocumentationMCPServer {
} }
} }
private async searchNodesFuzzy(query: string, limit: number): Promise<any> { private async searchNodesFuzzy(
query: string,
limit: number,
options?: {
includeOperations?: boolean;
}
): Promise<any> {
if (!this.db) throw new Error('Database not initialized'); if (!this.db) throw new Error('Database not initialized');
// Split into words for fuzzy matching // Split into words for fuzzy matching
@@ -1956,14 +2036,26 @@ export class N8NDocumentationMCPServer {
return { return {
query, query,
mode: 'FUZZY', mode: 'FUZZY',
results: matchingNodes.map(node => ({ results: matchingNodes.map(node => {
nodeType: node.node_type, const nodeResult: any = {
workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type), nodeType: node.node_type,
displayName: node.display_name, workflowNodeType: getWorkflowNodeType(node.package_name, node.node_type),
description: node.description, displayName: node.display_name,
category: node.category, description: node.description,
package: node.package_name category: node.category,
})), package: node.package_name
};
// Add operations tree if requested
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult;
}),
totalCount: matchingNodes.length totalCount: matchingNodes.length
}; };
} }
@@ -2068,6 +2160,7 @@ export class N8NDocumentationMCPServer {
options?: { options?: {
includeSource?: boolean; includeSource?: boolean;
includeExamples?: boolean; includeExamples?: boolean;
includeOperations?: boolean;
source?: 'all' | 'core' | 'community' | 'verified'; source?: 'all' | 'core' | 'community' | 'verified';
} }
): Promise<any> { ): Promise<any> {
@@ -2127,6 +2220,14 @@ export class N8NDocumentationMCPServer {
} }
} }
// Add operations tree if requested
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: rankedNodes.length totalCount: rankedNodes.length
@@ -2213,6 +2314,14 @@ export class N8NDocumentationMCPServer {
} }
} }
// Add operations tree if requested
if (options?.includeOperations) {
const opsTree = this.buildOperationsTree(node.operations);
if (opsTree) {
nodeResult.operationsTree = opsTree;
}
}
return nodeResult; return nodeResult;
}), }),
totalCount: rankedNodes.length totalCount: rankedNodes.length
@@ -2583,6 +2692,51 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
}; };
} }
/**
* Parse raw operations data and group by resource into a compact tree.
* Returns undefined when there are no operations (e.g. trigger nodes, Code node).
*/
private buildOperationsTree(operationsRaw: string | any[] | null | undefined): Array<{resource: string, operations: string[]}> | undefined {
if (!operationsRaw) return undefined;
let ops: any[];
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;
// Group by resource
const byResource = new Map<string, string[]>();
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
}));
}
private async getNodeEssentials(nodeType: string, includeExamples?: boolean): Promise<any> { private async getNodeEssentials(nodeType: string, includeExamples?: boolean): Promise<any> {
await this.ensureInitialized(); await this.ensureInitialized();
if (!this.repository) throw new Error('Repository not initialized'); if (!this.repository) throw new Error('Repository not initialized');
@@ -3780,6 +3934,71 @@ Full documentation is being prepared. For now, use get_node_essentials for confi
}; };
} }
private workflowPatternsCache: {
generatedAt: string;
templateCount: number;
categories: Record<string, {
templateCount: number;
pattern: string;
nodes?: Array<{ type: string; frequency: number; role: string; displayName: string }>;
commonChains?: Array<{ chain: string[]; count: number; frequency: number }>;
}>;
} | null = null;
private getWorkflowPatterns(category?: string, limit: number = 10): any {
// Load patterns file (cached after first load)
if (!this.workflowPatternsCache) {
try {
const patternsPath = path.join(__dirname, '..', '..', 'data', 'workflow-patterns.json');
if (existsSync(patternsPath)) {
this.workflowPatternsCache = JSON.parse(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) {
// 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,
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
})),
};
}
// Return overview of all categories
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.',
};
}
private async getTemplatesForTask(task: string, limit: number = 10, offset: number = 0): Promise<any> { private async getTemplatesForTask(task: string, limit: number = 10, offset: number = 0): Promise<any> {
await this.ensureInitialized(); await this.ensureInitialized();
if (!this.templateService) throw new Error('Template service not initialized'); if (!this.templateService) throw new Error('Template service not initialized');

View File

@@ -39,6 +39,25 @@ console.clear = () => {};
console.count = () => {}; console.count = () => {};
console.countReset = () => {}; console.countReset = () => {};
// CRITICAL: Intercept process.stdout.write to prevent non-JSON-RPC output (#628, #627, #567)
// Console suppression alone is insufficient — native modules (better-sqlite3), n8n packages,
// and third-party code can call process.stdout.write() directly, corrupting the JSON-RPC stream.
// Only allow writes that look like JSON-RPC messages; redirect everything else to stderr.
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
const stderrWrite = process.stderr.write.bind(process.stderr);
process.stdout.write = function (chunk: any, encodingOrCallback?: any, callback?: any): boolean {
const str = typeof chunk === 'string' ? chunk : chunk.toString();
// JSON-RPC messages are JSON objects with "jsonrpc" field — let those through
// The MCP SDK sends one JSON object per write call
const trimmed = str.trimStart();
if (trimmed.startsWith('{') && trimmed.includes('"jsonrpc"')) {
return originalStdoutWrite(chunk, encodingOrCallback, callback);
}
// Redirect everything else to stderr so it doesn't corrupt the protocol
return stderrWrite(chunk, encodingOrCallback, callback);
} as typeof process.stdout.write;
// Import and run the server AFTER suppressing output // Import and run the server AFTER suppressing output
import { N8NDocumentationMCPServer } from './server'; import { N8NDocumentationMCPServer } from './server';

View File

@@ -5,7 +5,7 @@ export const searchNodesDoc: ToolDocumentation = {
category: 'discovery', category: 'discovery',
essentials: { essentials: {
description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.', description: 'Text search across node names and descriptions. Returns most relevant nodes first, with frequently-used nodes (HTTP Request, Webhook, Set, Code, Slack) prioritized in results. Searches all 800+ nodes including 300+ verified community nodes.',
keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples'], keyParameters: ['query', 'mode', 'limit', 'source', 'includeExamples', 'includeOperations'],
example: 'search_nodes({query: "webhook"})', example: 'search_nodes({query: "webhook"})',
performance: '<20ms even for complex queries', performance: '<20ms even for complex queries',
tips: [ tips: [
@@ -14,7 +14,8 @@ export const searchNodesDoc: ToolDocumentation = {
'FUZZY mode: Handles typos and spelling errors', 'FUZZY mode: Handles typos and spelling errors',
'Use quotes for exact phrases: "google sheets"', 'Use quotes for exact phrases: "google sheets"',
'Use source="community" to search only community nodes', 'Use source="community" to search only community nodes',
'Use source="verified" for verified community nodes only' 'Use source="verified" for verified community nodes only',
'Use includeOperations=true to get resource/operation trees without a separate get_node call'
] ]
}, },
full: { full: {
@@ -24,20 +25,17 @@ export const searchNodesDoc: ToolDocumentation = {
limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false }, limit: { type: 'number', description: 'Maximum results to return. Default: 20, Max: 100', required: false },
mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false }, mode: { type: 'string', description: 'Search mode: "OR" (any word matches, default), "AND" (all words required), "FUZZY" (typo-tolerant)', required: false },
source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false }, source: { type: 'string', description: 'Filter by node source: "all" (default, everything), "core" (n8n base nodes only), "community" (community nodes only), "verified" (verified community nodes only)', required: false },
includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false } includeExamples: { type: 'boolean', description: 'Include top 2 real-world configuration examples from popular templates for each node. Default: false. Adds ~200-400 tokens per node.', required: false },
includeOperations: { type: 'boolean', description: 'Include resource/operation tree per node. Default: false. Adds ~100-300 tokens per result but saves a get_node round-trip. Only returned for nodes with resource/operation patterns — trigger nodes and freeform nodes (Code, HTTP Request) omit this field.', required: false }
}, },
returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.', returns: 'Array of node objects sorted by relevance score. Each object contains: nodeType, displayName, description, category, relevance score. For community nodes, also includes: isCommunity (boolean), isVerified (boolean), authorName (string), npmDownloads (number). Common nodes appear first when relevance is similar.',
examples: [ examples: [
'search_nodes({query: "webhook"}) - Returns Webhook node as top result', 'search_nodes({query: "webhook"}) - Returns Webhook node as top result',
'search_nodes({query: "database"}) - Returns MySQL, Postgres, MongoDB, Redis, etc.',
'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words', 'search_nodes({query: "google sheets", mode: "AND"}) - Requires both words',
'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo', 'search_nodes({query: "slak", mode: "FUZZY"}) - Finds Slack despite typo',
'search_nodes({query: "http api"}) - Finds HTTP Request, GraphQL, REST nodes',
'search_nodes({query: "transform data"}) - Finds Set, Code, Function, Item Lists nodes',
'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes', 'search_nodes({query: "scraping", source: "community"}) - Find community scraping nodes',
'search_nodes({query: "pdf", source: "verified"}) - Find verified community PDF nodes', 'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples',
'search_nodes({query: "brightdata"}) - Find BrightData community node', 'search_nodes({query: "slack", includeOperations: true}) - Get Slack with resource/operation tree (7 resources, 44 ops)'
'search_nodes({query: "slack", includeExamples: true}) - Get Slack with template examples'
], ],
useCases: [ useCases: [
'Finding nodes when you know partial names', 'Finding nodes when you know partial names',

View File

@@ -23,7 +23,8 @@ import {
n8nExecutionsDoc, n8nExecutionsDoc,
n8nWorkflowVersionsDoc, n8nWorkflowVersionsDoc,
n8nDeployTemplateDoc, n8nDeployTemplateDoc,
n8nManageDatatableDoc n8nManageDatatableDoc,
n8nGenerateWorkflowDoc
} from './workflow_management'; } from './workflow_management';
// Combine all tool documentations into a single object // Combine all tool documentations into a single object
@@ -62,7 +63,8 @@ export const toolsDocumentation: Record<string, ToolDocumentation> = {
n8n_executions: n8nExecutionsDoc, n8n_executions: n8nExecutionsDoc,
n8n_workflow_versions: n8nWorkflowVersionsDoc, n8n_workflow_versions: n8nWorkflowVersionsDoc,
n8n_deploy_template: n8nDeployTemplateDoc, n8n_deploy_template: n8nDeployTemplateDoc,
n8n_manage_datatable: n8nManageDatatableDoc n8n_manage_datatable: n8nManageDatatableDoc,
n8n_generate_workflow: n8nGenerateWorkflowDoc
}; };
// Re-export types // Re-export types

View File

@@ -4,7 +4,7 @@ export const searchTemplatesDoc: ToolDocumentation = {
name: 'search_templates', name: 'search_templates',
category: 'templates', category: 'templates',
essentials: { essentials: {
description: 'Unified template search with multiple modes: keyword search, by node types, by task type, or by metadata. 2,700+ templates available.', description: 'Unified template search with multiple modes: keyword search, by node types, by task type, by metadata, or patterns. 2,700+ templates available.',
keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'], keyParameters: ['searchMode', 'query', 'nodeTypes', 'task', 'limit'],
example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})', example: 'search_templates({searchMode: "by_task", task: "webhook_processing"})',
performance: 'Fast (<100ms) - FTS5 full-text search', performance: 'Fast (<100ms) - FTS5 full-text search',
@@ -12,7 +12,9 @@ export const searchTemplatesDoc: ToolDocumentation = {
'searchMode="keyword" (default): Search by name/description', 'searchMode="keyword" (default): Search by name/description',
'searchMode="by_nodes": Find templates using specific nodes', 'searchMode="by_nodes": Find templates using specific nodes',
'searchMode="by_task": Get curated templates for common tasks', 'searchMode="by_task": Get curated templates for common tasks',
'searchMode="by_metadata": Filter by complexity, services, audience' 'searchMode="by_metadata": Filter by complexity, services, audience',
'searchMode="patterns": Workflow pattern summaries across 10 task categories',
'patterns without task: overview of all categories. patterns with task: node frequencies + connection chains'
] ]
}, },
full: { full: {
@@ -21,14 +23,15 @@ export const searchTemplatesDoc: ToolDocumentation = {
- by_nodes: Find templates that use specific node types - by_nodes: Find templates that use specific node types
- by_task: Get curated templates for predefined task categories - by_task: Get curated templates for predefined task categories
- by_metadata: Filter by complexity, setup time, required services, or target audience - by_metadata: Filter by complexity, setup time, required services, or target audience
- patterns: Lightweight workflow pattern summaries mined from 2,700+ templates
**Available Task Types (for searchMode="by_task"):** **Available Task Types (for searchMode="by_task" and "patterns"):**
ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`, ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations`,
parameters: { parameters: {
searchMode: { searchMode: {
type: 'string', type: 'string',
required: false, required: false,
description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata"' description: 'Search mode: "keyword" (default), "by_nodes", "by_task", "by_metadata", "patterns"'
}, },
query: { query: {
type: 'string', type: 'string',
@@ -43,7 +46,7 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
task: { task: {
type: 'string', type: 'string',
required: false, required: false,
description: 'For searchMode=by_task: Task type (ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations)' description: 'For searchMode=by_task: Task type. For searchMode=patterns: optional category filter (omit for overview of all categories). Values: ai_automation, data_sync, webhook_processing, email_automation, slack_integration, data_transformation, file_processing, scheduling, api_integration, database_operations'
}, },
complexity: { complexity: {
type: 'string', type: 'string',
@@ -91,38 +94,45 @@ ai_automation, data_sync, webhook_processing, email_automation, slack_integratio
description: 'Pagination offset (default 0)' description: 'Pagination offset (default 0)'
} }
}, },
returns: `Returns an object containing: returns: `For keyword/by_nodes/by_task/by_metadata modes:
- templates: Array of matching templates - templates: Array of matching templates
- id: Template ID for get_template() - id: Template ID for get_template()
- name: Template name - name, description, author, nodes, views, created, url, metadata
- description: What the workflow does
- author: Creator information
- nodes: Array of node types used
- views: Popularity metric
- created: Creation date
- url: Link to template
- metadata: AI-generated metadata (complexity, services, etc.)
- totalFound: Total matching templates - totalFound: Total matching templates
- searchMode: The mode used`, - searchMode: The mode used
For patterns mode (no task):
- templateCount, generatedAt
- categories: Array of {category, templateCount, pattern, topNodes}
- tip: How to drill into a specific category
For patterns mode (with task):
- category, templateCount, pattern
- nodes: Array of {type, freq, role} (top nodes by frequency, limited by 'limit')
- chains: Array of {path, count, freq} (top 5 connection chains, short node names)`,
examples: [ examples: [
'// Keyword search (default)\nsearch_templates({query: "chatbot"})', '// Keyword search (default)\nsearch_templates({query: "chatbot"})',
'// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})', '// Find templates using specific nodes\nsearch_templates({searchMode: "by_nodes", nodeTypes: ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"]})',
'// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})', '// Get templates for a task type\nsearch_templates({searchMode: "by_task", task: "webhook_processing"})',
'// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})', '// Filter by metadata\nsearch_templates({searchMode: "by_metadata", complexity: "simple", requiredService: "openai"})',
'// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})' '// Combine metadata filters\nsearch_templates({searchMode: "by_metadata", maxSetupMinutes: 30, targetAudience: "developers"})',
'// Pattern overview — all categories with top nodes (~550 tokens)\nsearch_templates({searchMode: "patterns"})',
'// Detailed patterns for a category — node frequencies + connection chains\nsearch_templates({searchMode: "patterns", task: "ai_automation"})'
], ],
useCases: [ useCases: [
'Find workflows by business purpose (keyword search)', 'Find workflows by business purpose (keyword search)',
'Find templates using specific integrations (by_nodes)', 'Find templates using specific integrations (by_nodes)',
'Get pre-built solutions for common tasks (by_task)', 'Get pre-built solutions for common tasks (by_task)',
'Filter by complexity for team skill level (by_metadata)', 'Filter by complexity for team skill level (by_metadata)',
'Find templates requiring specific services (by_metadata)' 'Understand common workflow shapes before building (patterns)',
'Architecture planning — which nodes go together (patterns)'
], ],
performance: `Fast performance across all modes: performance: `Fast performance across all modes:
- keyword: <50ms with FTS5 indexing - keyword: <50ms with FTS5 indexing
- by_nodes: <100ms with indexed lookups - by_nodes: <100ms with indexed lookups
- by_task: <50ms from curated cache - by_task: <50ms from curated cache
- by_metadata: <100ms with filtered queries`, - by_metadata: <100ms with filtered queries
- patterns: <10ms (pre-mined, cached in memory)`,
bestPractices: [ bestPractices: [
'Use searchMode="by_task" for common automation patterns', 'Use searchMode="by_task" for common automation patterns',
'Use searchMode="by_nodes" when you know which integrations you need', 'Use searchMode="by_nodes" when you know which integrations you need',

View File

@@ -11,3 +11,4 @@ export { n8nExecutionsDoc } from './n8n-executions';
export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions'; export { n8nWorkflowVersionsDoc } from './n8n-workflow-versions';
export { n8nDeployTemplateDoc } from './n8n-deploy-template'; export { n8nDeployTemplateDoc } from './n8n-deploy-template';
export { n8nManageDatatableDoc } from './n8n-manage-datatable'; export { n8nManageDatatableDoc } from './n8n-manage-datatable';
export { n8nGenerateWorkflowDoc } from './n8n-generate-workflow';

View File

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

View File

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

View File

@@ -654,4 +654,44 @@ export const n8nManagementTools: ToolDefinition[] = [
openWorldHint: true, openWorldHint: true,
}, },
}, },
{
name: 'n8n_generate_workflow',
description: 'Generate an n8n workflow from a natural language description using AI. ' +
'Call with just a description to get workflow proposals. ' +
'Then call again with deploy_id to deploy a chosen proposal, ' +
'or set skip_cache=true to generate a fresh workflow. ' +
'Use confirm_deploy=true to deploy a previously generated workflow.',
inputSchema: {
type: 'object',
properties: {
description: {
type: 'string',
description: 'Clear description of what the workflow should do. Include: trigger type ' +
'(webhook, schedule, manual), services to integrate (Slack, Gmail, etc.), and the logic/flow.'
},
skip_cache: {
type: 'boolean',
description: 'Set to true to skip proposals and generate a fresh workflow from scratch. ' +
'Returns a preview — call again with confirm_deploy=true to deploy it.'
},
deploy_id: {
type: 'string',
description: 'ID of a proposal to deploy. Get proposal IDs from a previous call ' +
'that returned status "proposals".'
},
confirm_deploy: {
type: 'boolean',
description: 'Set to true to deploy the workflow from the last generation preview.'
}
},
required: ['description'],
},
annotations: {
title: 'Generate Workflow',
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: true,
},
},
]; ];

View File

@@ -57,6 +57,11 @@ export const n8nDocumentationToolsFinal: ToolDefinition[] = [
description: 'Include top 2 real-world configuration examples from popular templates (default: false)', description: 'Include top 2 real-world configuration examples from popular templates (default: false)',
default: false, default: false,
}, },
includeOperations: {
type: 'boolean',
default: false,
description: 'Include resource/operation tree per node. Adds ~100-300 tokens per result but saves a get_node round-trip.',
},
source: { source: {
type: 'string', type: 'string',
enum: ['all', 'core', 'community', 'verified'], enum: ['all', 'core', 'community', 'verified'],
@@ -242,14 +247,14 @@ export const n8nDocumentationToolsFinal: ToolDefinition[] = [
}, },
{ {
name: 'search_templates', name: 'search_templates',
description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services.`, description: `Search templates with multiple modes. Use searchMode='keyword' for text search, 'by_nodes' to find templates using specific nodes, 'by_task' for curated task-based templates, 'by_metadata' for filtering by complexity/setup time/services, 'patterns' for lightweight workflow pattern summaries mined from 2700+ templates.`,
inputSchema: { inputSchema: {
type: 'object', type: 'object',
properties: { properties: {
searchMode: { searchMode: {
type: 'string', type: 'string',
enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata'], enum: ['keyword', 'by_nodes', 'by_task', 'by_metadata', 'patterns'],
description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services', description: 'Search mode. keyword=text search (default), by_nodes=find by node types, by_task=curated task templates, by_metadata=filter by complexity/services, patterns=lightweight workflow pattern summaries',
default: 'keyword', default: 'keyword',
}, },
// For searchMode='keyword' // For searchMode='keyword'
@@ -271,7 +276,7 @@ export const n8nDocumentationToolsFinal: ToolDefinition[] = [
items: { type: 'string' }, items: { type: 'string' },
description: 'For searchMode=by_nodes: array of node types (e.g., ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"])', description: 'For searchMode=by_nodes: array of node types (e.g., ["n8n-nodes-base.httpRequest", "n8n-nodes-base.slack"])',
}, },
// For searchMode='by_task' // For searchMode='by_task' or 'patterns'
task: { task: {
type: 'string', type: 'string',
enum: [ enum: [
@@ -286,7 +291,7 @@ export const n8nDocumentationToolsFinal: ToolDefinition[] = [
'api_integration', 'api_integration',
'database_operations' 'database_operations'
], ],
description: 'For searchMode=by_task: the type of task', description: 'For searchMode=by_task: the type of task. For searchMode=patterns: optional category filter (omit for overview of all categories).',
}, },
// For searchMode='by_metadata' // For searchMode='by_metadata'
category: { category: {

View File

@@ -131,18 +131,23 @@ export class PropertyExtractor {
} }
} }
// Programmatic nodes - look for operation property in properties // Programmatic nodes - look for operation properties in properties
// Note: nodes can have MULTIPLE operation properties, each with displayOptions.show.resource
// mapping to a different resource (e.g., Slack has 7 operation props for channel, message, etc.)
if (description.properties && Array.isArray(description.properties)) { if (description.properties && Array.isArray(description.properties)) {
const operationProp = description.properties.find( const operationProps = description.properties.filter(
(p: any) => p.name === 'operation' || p.name === 'action' (p: any) => p.name === 'operation' || p.name === 'action'
); );
if (operationProp?.options) { for (const operationProp of operationProps) {
if (!operationProp?.options) continue;
const resource = operationProp.displayOptions?.show?.resource?.[0];
operationProp.options.forEach((op: any) => { operationProp.options.forEach((op: any) => {
operations.push({ operations.push({
operation: op.value, operation: op.value,
name: op.name, name: op.name,
description: op.description description: op.description,
...(resource ? { resource } : {})
}); });
}); });
} }

View File

@@ -0,0 +1,532 @@
#!/usr/bin/env node
import { createDatabaseAdapter } from '../database/database-adapter';
import * as zlib from 'zlib';
import * as fs from 'fs';
import * as path from 'path';
// Node types to exclude from analysis
const EXCLUDED_TYPES = new Set([
'n8n-nodes-base.stickyNote',
'n8n-nodes-base.noOp',
'n8n-nodes-base.manualTrigger',
]);
// Category-to-node mapping for classification
const TASK_NODE_MAPPING: Record<string, string[]> = {
ai_automation: [
'nodes-langchain.agent', 'nodes-langchain.openAi', 'nodes-langchain.chainLlm',
'nodes-langchain.lmChatOpenAi', 'nodes-langchain.lmChatAnthropic',
'nodes-langchain.chainSummarization', 'nodes-langchain.toolWorkflow',
'nodes-langchain.memoryBufferWindow', 'nodes-langchain.outputParserStructured',
],
webhook_processing: [
'nodes-base.webhook', 'nodes-base.respondToWebhook',
],
email_automation: [
'nodes-base.gmail', 'nodes-base.emailSend', 'nodes-base.microsoftOutlook',
'nodes-base.emailReadImap',
],
slack_integration: [
'nodes-base.slack', 'nodes-base.slackTrigger',
],
data_sync: [
'nodes-base.googleSheets', 'nodes-base.airtable', 'nodes-base.postgres',
'nodes-base.mysql', 'nodes-base.mongoDb',
],
data_transformation: [
'nodes-base.set', 'nodes-base.code', 'nodes-base.splitInBatches',
'nodes-base.merge', 'nodes-base.itemLists', 'nodes-base.filter',
'nodes-base.if', 'nodes-base.switch',
],
scheduling: [
'nodes-base.scheduleTrigger', 'nodes-base.cron',
],
api_integration: [
'nodes-base.httpRequest', 'nodes-base.webhook', 'nodes-base.graphql',
],
database_operations: [
'nodes-base.postgres', 'nodes-base.mongoDb', 'nodes-base.redis',
'nodes-base.mysql', 'nodes-base.mySql',
],
file_processing: [
'nodes-base.readBinaryFiles', 'nodes-base.writeBinaryFile',
'nodes-base.spreadsheetFile', 'nodes-base.googleDrive',
],
};
// Display name mapping for common node types (used for pattern strings)
const DISPLAY_NAMES: Record<string, string> = {
'n8n-nodes-base.webhook': 'Webhook',
'n8n-nodes-base.httpRequest': 'HTTP Request',
'n8n-nodes-base.code': 'Code',
'n8n-nodes-base.set': 'Set',
'n8n-nodes-base.if': 'If',
'n8n-nodes-base.switch': 'Switch',
'n8n-nodes-base.merge': 'Merge',
'n8n-nodes-base.filter': 'Filter',
'n8n-nodes-base.splitInBatches': 'Split In Batches',
'n8n-nodes-base.itemLists': 'Item Lists',
'n8n-nodes-base.respondToWebhook': 'Respond to Webhook',
'n8n-nodes-base.gmail': 'Gmail',
'n8n-nodes-base.emailSend': 'Send Email',
'n8n-nodes-base.slack': 'Slack',
'n8n-nodes-base.slackTrigger': 'Slack Trigger',
'n8n-nodes-base.googleSheets': 'Google Sheets',
'n8n-nodes-base.airtable': 'Airtable',
'n8n-nodes-base.postgres': 'Postgres',
'n8n-nodes-base.mysql': 'MySQL',
'n8n-nodes-base.mongoDb': 'MongoDB',
'n8n-nodes-base.redis': 'Redis',
'n8n-nodes-base.scheduleTrigger': 'Schedule Trigger',
'n8n-nodes-base.cron': 'Cron',
'n8n-nodes-base.googleDrive': 'Google Drive',
'n8n-nodes-base.spreadsheetFile': 'Spreadsheet File',
'n8n-nodes-base.readBinaryFiles': 'Read Binary Files',
'n8n-nodes-base.writeBinaryFile': 'Write Binary File',
'n8n-nodes-base.graphql': 'GraphQL',
'n8n-nodes-base.microsoftOutlook': 'Microsoft Outlook',
'n8n-nodes-base.emailReadImap': 'Email (IMAP)',
'n8n-nodes-base.noOp': 'No Op',
'@n8n/n8n-nodes-langchain.agent': 'AI Agent',
'@n8n/n8n-nodes-langchain.openAi': 'OpenAI',
'@n8n/n8n-nodes-langchain.chainLlm': 'LLM Chain',
'@n8n/n8n-nodes-langchain.lmChatOpenAi': 'OpenAI Chat Model',
'@n8n/n8n-nodes-langchain.lmChatAnthropic': 'Anthropic Chat Model',
'@n8n/n8n-nodes-langchain.chainSummarization': 'Summarization Chain',
'@n8n/n8n-nodes-langchain.toolWorkflow': 'Workflow Tool',
'@n8n/n8n-nodes-langchain.memoryBufferWindow': 'Window Buffer Memory',
'@n8n/n8n-nodes-langchain.outputParserStructured': 'Structured Output Parser',
'n8n-nodes-base.manualTrigger': 'Manual Trigger',
};
/**
* Check if a node type matches a category mapping entry.
* Category mappings use short forms like 'nodes-base.webhook'
* while actual types may be 'n8n-nodes-base.webhook' or '@n8n/n8n-nodes-langchain.agent'.
*/
function matchesCategory(nodeType: string, categoryPattern: string): boolean {
return nodeType.endsWith(categoryPattern) || nodeType.includes(categoryPattern);
}
/**
* Get display name for a node type.
*/
function getDisplayName(nodeType: string): string {
if (DISPLAY_NAMES[nodeType]) {
return DISPLAY_NAMES[nodeType];
}
// Extract the last part after the last dot
const parts = nodeType.split('.');
const name = parts[parts.length - 1];
// Convert camelCase to Title Case
return name
.replace(/([A-Z])/g, ' $1')
.replace(/^./, s => s.toUpperCase())
.trim();
}
/**
* Determine if a node type is a trigger node.
*/
function isTriggerType(nodeType: string): boolean {
const lower = nodeType.toLowerCase();
return lower.includes('trigger') || lower.includes('webhook');
}
/**
* Classify a set of node types into categories.
*/
function classifyTemplate(nodeTypes: string[], metadataCategories?: string[]): string[] {
const categories = new Set<string>();
for (const nodeType of nodeTypes) {
for (const [category, patterns] of Object.entries(TASK_NODE_MAPPING)) {
for (const pattern of patterns) {
if (matchesCategory(nodeType, pattern)) {
categories.add(category);
}
}
}
}
// Also include categories from metadata_json if available
if (metadataCategories && Array.isArray(metadataCategories)) {
for (const cat of metadataCategories) {
const normalized = cat.toLowerCase().replace(/[\s-]+/g, '_');
// Map metadata categories to our category keys
for (const key of Object.keys(TASK_NODE_MAPPING)) {
if (normalized.includes(key) || key.includes(normalized)) {
categories.add(key);
}
}
}
}
return Array.from(categories);
}
interface NodeFrequency {
type: string;
count: number;
frequency: number;
displayName: string;
}
interface EdgeFrequency {
from: string;
to: string;
count: number;
}
interface ChainFrequency {
chain: string[];
count: number;
frequency: number;
}
interface CategoryData {
templateCount: number;
pattern: string;
nodes: Array<{ type: string; frequency: number; role: string; displayName: string }>;
commonChains: ChainFrequency[];
}
interface PatternOutput {
generatedAt: string;
templateCount: number;
categories: Record<string, CategoryData>;
global: {
topNodes: NodeFrequency[];
topEdges: EdgeFrequency[];
};
}
async function main(): Promise<void> {
const dbPath = path.resolve(__dirname, '../../data/nodes.db');
console.log(`Opening database: ${dbPath}`);
const db = await createDatabaseAdapter(dbPath);
// ---- Pass 1: Frequency & co-occurrence ----
console.log('\n=== Pass 1: Node frequency & co-occurrence ===');
const pass1Start = Date.now();
const lightRows = db.prepare(
'SELECT id, nodes_used, metadata_json, views FROM templates ORDER BY views DESC'
).all() as Array<{ id: number; nodes_used: string | null; metadata_json: string | null; views: number }>;
const templateCount = lightRows.length;
console.log(`Found ${templateCount} templates`);
// Global counters
const nodeFrequency = new Map<string, number>();
const pairCooccurrence = new Map<string, number>();
// Per-category tracking
const categoryTemplates = new Map<string, Set<number>>();
const categoryNodes = new Map<string, Map<string, number>>();
for (let i = 0; i < lightRows.length; i++) {
const row = lightRows[i];
if (i > 0 && i % 500 === 0) {
console.log(` Processing template ${i}/${templateCount}...`);
}
if (!row.nodes_used) continue;
let nodeTypes: string[];
try {
nodeTypes = JSON.parse(row.nodes_used);
if (!Array.isArray(nodeTypes)) continue;
} catch {
continue;
}
// Deduplicate and filter
const uniqueTypes = [...new Set(nodeTypes)].filter(t => !EXCLUDED_TYPES.has(t));
if (uniqueTypes.length === 0) continue;
// Count global frequency
for (const nodeType of uniqueTypes) {
nodeFrequency.set(nodeType, (nodeFrequency.get(nodeType) || 0) + 1);
}
// Count pairwise co-occurrence
for (let a = 0; a < uniqueTypes.length; a++) {
for (let b = a + 1; b < uniqueTypes.length; b++) {
const pair = [uniqueTypes[a], uniqueTypes[b]].sort().join('|||');
pairCooccurrence.set(pair, (pairCooccurrence.get(pair) || 0) + 1);
}
}
// Classify into categories
let metadataCategories: string[] | undefined;
if (row.metadata_json) {
try {
const meta = JSON.parse(row.metadata_json);
metadataCategories = meta.categories;
} catch {
// skip
}
}
const categories = classifyTemplate(uniqueTypes, metadataCategories);
for (const cat of categories) {
if (!categoryTemplates.has(cat)) {
categoryTemplates.set(cat, new Set());
categoryNodes.set(cat, new Map());
}
categoryTemplates.get(cat)!.add(row.id);
const catNodeMap = categoryNodes.get(cat)!;
for (const nodeType of uniqueTypes) {
catNodeMap.set(nodeType, (catNodeMap.get(nodeType) || 0) + 1);
}
}
}
const pass1Time = ((Date.now() - pass1Start) / 1000).toFixed(1);
console.log(`Pass 1 complete: ${pass1Time}s`);
console.log(` Unique node types: ${nodeFrequency.size}`);
console.log(` Categories found: ${categoryTemplates.size}`);
// ---- Pass 2: Connection topology ----
console.log('\n=== Pass 2: Connection topology ===');
const pass2Start = Date.now();
const compressedRows = db.prepare(
'SELECT id, nodes_used, workflow_json_compressed, views FROM templates ORDER BY views DESC'
).all() as Array<{ id: number; nodes_used: string | null; workflow_json_compressed: string | null; views: number }>;
// Edge frequency: sourceType -> targetType
const edgeFrequency = new Map<string, number>();
// Chain frequency (by category)
const categoryChains = new Map<string, Map<string, number>>();
// Global chains
const globalChains = new Map<string, number>();
let decompressedCount = 0;
let decompressFailCount = 0;
for (let i = 0; i < compressedRows.length; i++) {
const row = compressedRows[i];
if (i > 0 && i % 500 === 0) {
console.log(` Processing template ${i}/${templateCount}...`);
}
if (!row.workflow_json_compressed) continue;
let workflow: any;
try {
const decompressed = zlib.gunzipSync(Buffer.from(row.workflow_json_compressed, 'base64'));
workflow = JSON.parse(decompressed.toString());
decompressedCount++;
} catch {
decompressFailCount++;
continue;
}
const nodes: any[] = workflow.nodes || [];
const connections: Record<string, any> = workflow.connections || {};
// Build name -> type map
const nameToType = new Map<string, string>();
for (const node of nodes) {
if (node.name && node.type && !EXCLUDED_TYPES.has(node.type)) {
nameToType.set(node.name, node.type);
}
}
// Build adjacency list for BFS
const adjacency = new Map<string, string[]>();
// Parse connections and record edges
for (const sourceName of Object.keys(connections)) {
const sourceType = nameToType.get(sourceName);
if (!sourceType) continue;
const mainOutputs = connections[sourceName]?.main;
if (!Array.isArray(mainOutputs)) continue;
for (const outputGroup of mainOutputs) {
if (!Array.isArray(outputGroup)) continue;
for (const conn of outputGroup) {
if (!conn || !conn.node) continue;
const targetName = conn.node;
const targetType = nameToType.get(targetName);
if (!targetType) continue;
// Record edge
const edgeKey = `${sourceType}|||${targetType}`;
edgeFrequency.set(edgeKey, (edgeFrequency.get(edgeKey) || 0) + 1);
// Build adjacency for chain extraction
if (!adjacency.has(sourceName)) {
adjacency.set(sourceName, []);
}
adjacency.get(sourceName)!.push(targetName);
}
}
}
// Find trigger nodes (nodes with no incoming connections, or type contains 'Trigger')
const hasIncoming = new Set<string>();
for (const targets of adjacency.values()) {
for (const target of targets) {
hasIncoming.add(target);
}
}
const triggerNodes = nodes.filter(n => {
if (EXCLUDED_TYPES.has(n.type)) return false;
return !hasIncoming.has(n.name) || isTriggerType(n.type);
});
// Pre-compute categories for this template (avoids re-parsing nodes_used per chain)
let templateCategories: string[] = [];
try {
if (row.nodes_used) {
const parsed = JSON.parse(row.nodes_used);
if (Array.isArray(parsed)) {
templateCategories = classifyTemplate(parsed.filter((t: string) => !EXCLUDED_TYPES.has(t)));
}
}
} catch {
// skip
}
// BFS from each trigger, extract chains of length 2-4
for (const trigger of triggerNodes) {
const queue: Array<{ nodeName: string; path: string[] }> = [
{ nodeName: trigger.name, path: [nameToType.get(trigger.name)!] },
];
const visited = new Set<string>([trigger.name]);
while (queue.length > 0) {
const { nodeName, path: currentPath } = queue.shift()!;
// Record chains of length 2, 3, 4
if (currentPath.length >= 2 && currentPath.length <= 4) {
const chainKey = currentPath.join('|||');
globalChains.set(chainKey, (globalChains.get(chainKey) || 0) + 1);
for (const cat of templateCategories) {
if (!categoryChains.has(cat)) {
categoryChains.set(cat, new Map());
}
const catChainMap = categoryChains.get(cat)!;
catChainMap.set(chainKey, (catChainMap.get(chainKey) || 0) + 1);
}
}
// Stop extending at depth 4
if (currentPath.length >= 4) continue;
const neighbors = adjacency.get(nodeName) || [];
for (const neighbor of neighbors) {
if (visited.has(neighbor)) continue;
const neighborType = nameToType.get(neighbor);
if (!neighborType) continue;
visited.add(neighbor);
queue.push({ nodeName: neighbor, path: [...currentPath, neighborType] });
}
}
}
}
const pass2Time = ((Date.now() - pass2Start) / 1000).toFixed(1);
console.log(`Pass 2 complete: ${pass2Time}s`);
console.log(` Decompressed: ${decompressedCount}, Failed: ${decompressFailCount}`);
console.log(` Unique edges: ${edgeFrequency.size}`);
console.log(` Unique chains: ${globalChains.size}`);
// ---- Build output ----
console.log('\n=== Building output ===');
// Global top nodes
const topNodes: NodeFrequency[] = [...nodeFrequency.entries()]
.sort(([, a], [, b]) => b - a)
.slice(0, 50)
.map(([type, count]) => ({
type,
count,
frequency: Math.round((count / templateCount) * 100) / 100,
displayName: getDisplayName(type),
}));
// Global top edges
const topEdges: EdgeFrequency[] = [...edgeFrequency.entries()]
.sort(([, a], [, b]) => b - a)
.slice(0, 50)
.map(([key, count]) => {
const [from, to] = key.split('|||');
return { from, to, count };
});
// Build category data
const categories: Record<string, CategoryData> = {};
for (const [cat, templateIds] of categoryTemplates.entries()) {
const catNodeMap = categoryNodes.get(cat)!;
const catTemplateCount = templateIds.size;
// Top nodes for category, sorted by frequency
const catTopNodes = [...catNodeMap.entries()]
.sort(([, a], [, b]) => b - a)
.slice(0, 20)
.map(([type, count]) => ({
type,
frequency: Math.round((count / catTemplateCount) * 100) / 100,
role: isTriggerType(type) ? 'trigger' : 'action',
displayName: getDisplayName(type),
}));
// Top chains for category
const catChainMap = categoryChains.get(cat) || new Map<string, number>();
const catTopChains: ChainFrequency[] = [...catChainMap.entries()]
.sort(([, a], [, b]) => b - a)
.slice(0, 10)
.map(([chainKey, count]) => ({
chain: chainKey.split('|||'),
count,
frequency: Math.round((count / catTemplateCount) * 100) / 100,
}));
// Generate pattern string from top nodes
// Order: triggers first, then transforms/logic, then actions
const triggerNodes = catTopNodes.filter(n => n.role === 'trigger').slice(0, 1);
const actionNodes = catTopNodes.filter(n => n.role !== 'trigger').slice(0, 3);
const patternParts = [...triggerNodes, ...actionNodes].map(n => n.displayName);
const pattern = patternParts.join(' \u2192 ') || 'Mixed workflow';
categories[cat] = {
templateCount: catTemplateCount,
pattern,
nodes: catTopNodes,
commonChains: catTopChains,
};
}
const output: PatternOutput = {
generatedAt: new Date().toISOString(),
templateCount,
categories,
global: {
topNodes,
topEdges,
},
};
// Write output
const outputPath = path.resolve(__dirname, '../../data/workflow-patterns.json');
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
console.log(`\nWritten ${Object.keys(categories).length} categories, ${templateCount} templates analyzed`);
console.log(`Output: ${outputPath}`);
console.log(`Pass 1: ${pass1Time}s, Pass 2: ${pass2Time}s`);
console.log(`Total: ${((Date.now() - pass1Start) / 1000).toFixed(1)}s`);
db.close();
}
main().catch((err) => {
console.error('Error:', err);
process.exit(1);
});

View File

@@ -19,6 +19,18 @@ interface ExpressionContext {
} }
export class ExpressionValidator { export class ExpressionValidator {
// Bare n8n variable references missing {{ }} wrappers
private static readonly BARE_EXPRESSION_PATTERNS: Array<{ pattern: RegExp; name: string }> = [
{ 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' },
];
// Common n8n expression patterns // Common n8n expression patterns
private static readonly EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g; private static readonly EXPRESSION_PATTERN = /\{\{([\s\S]+?)\}\}/g;
private static readonly VARIABLE_PATTERNS = { private static readonly VARIABLE_PATTERNS = {
@@ -288,6 +300,32 @@ export class ExpressionValidator {
return combinedResult; return combinedResult;
} }
/**
* Detect bare n8n variable references missing {{ }} wrappers.
* Emits warnings since the value is technically valid as a literal string.
*/
private static checkBareExpression(
value: string,
path: string,
result: ExpressionValidationResult
): void {
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;
}
}
}
/** /**
* Recursively validate expressions in parameters * Recursively validate expressions in parameters
*/ */
@@ -307,6 +345,9 @@ export class ExpressionValidator {
} }
if (typeof obj === 'string') { if (typeof obj === 'string') {
// Detect bare expressions missing {{ }} wrappers
this.checkBareExpression(obj, path, result);
if (obj.includes('{{')) { if (obj.includes('{{')) {
const validation = this.validateExpression(obj, context); const validation = this.validateExpression(obj, context);

View File

@@ -344,10 +344,10 @@ export function validateWorkflowStructure(workflow: Partial<Workflow>): string[]
}); });
} }
// Validate filter-based nodes (IF v2.2+, Switch v3.2+) have complete metadata // Validate If/Switch condition structures (version-conditional)
if (workflow.nodes) { if (workflow.nodes) {
workflow.nodes.forEach((node, index) => { workflow.nodes.forEach((node, index) => {
const filterErrors = validateFilterBasedNodeMetadata(node); const filterErrors = validateConditionNodeStructure(node);
if (filterErrors.length > 0) { if (filterErrors.length > 0) {
errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`)); errors.push(...filterErrors.map(err => `Node "${node.name}" (index ${index}): ${err}`));
} }
@@ -488,106 +488,81 @@ export function hasWebhookTrigger(workflow: Workflow): boolean {
} }
/** /**
* Validate filter-based node metadata (IF v2.2+, Switch v3.2+) * Validate If/Switch node conditions structure for ANY version.
* Returns array of error messages * Version-conditional: validates the correct structure per version.
*/ */
export function validateFilterBasedNodeMetadata(node: WorkflowNode): string[] { export function validateConditionNodeStructure(node: WorkflowNode): string[] {
const errors: string[] = []; const errors: string[] = [];
const typeVersion = node.typeVersion || 1;
// Check if node is filter-based if (node.type === 'n8n-nodes-base.if') {
const isIFNode = node.type === 'n8n-nodes-base.if' && node.typeVersion >= 2.2; if (typeVersion >= 2.2) {
const isSwitchNode = node.type === 'n8n-nodes-base.switch' && node.typeVersion >= 3.2; errors.push(...validateFilterOptionsRequired(node.parameters?.conditions, 'conditions'));
errors.push(...validateFilterConditionOperators(node.parameters?.conditions, 'conditions'));
if (!isIFNode && !isSwitchNode) { } else if (typeVersion >= 2) {
return errors; // Not a filter-based node // v2 has conditions but no options requirement; just validate operators
} errors.push(...validateFilterConditionOperators(node.parameters?.conditions as any, 'conditions'));
}
// Validate IF node } else if (node.type === 'n8n-nodes-base.switch') {
if (isIFNode) { if (typeVersion >= 3.2) {
const conditions = (node.parameters.conditions as any); const rules = node.parameters?.rules as any;
if (rules?.rules && Array.isArray(rules.rules)) {
// Check conditions.options exists rules.rules.forEach((rule: any, i: number) => {
if (!conditions?.options) { errors.push(...validateFilterOptionsRequired(rule.conditions, `rules.rules[${i}].conditions`));
errors.push( errors.push(...validateFilterConditionOperators(rule.conditions, `rules.rules[${i}].conditions`));
'Missing required "conditions.options". ' + });
'IF v2.2+ requires: {version: 2, leftValue: "", caseSensitive: true, typeValidation: "strict"}'
);
} else {
// Validate required fields
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}`
);
}
} }
} }
// Validate operators in conditions
if (conditions?.conditions && Array.isArray(conditions.conditions)) {
conditions.conditions.forEach((condition: any, i: number) => {
const operatorErrors = validateOperatorStructure(condition.operator, `conditions.conditions[${i}].operator`);
errors.push(...operatorErrors);
});
}
}
// Validate Switch node
if (isSwitchNode) {
const rules = (node.parameters.rules as any);
if (rules?.rules && Array.isArray(rules.rules)) {
rules.rules.forEach((rule: any, ruleIndex: number) => {
// Check rule.conditions.options
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 {
// Validate required fields
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}`
);
}
}
}
// Validate operators in rule conditions
if (rule.conditions?.conditions && Array.isArray(rule.conditions.conditions)) {
rule.conditions.conditions.forEach((condition: any, condIndex: number) => {
const operatorErrors = validateOperatorStructure(
condition.operator,
`rules.rules[${ruleIndex}].conditions.conditions[${condIndex}].operator`
);
errors.push(...operatorErrors);
});
}
});
}
} }
return errors; return errors;
} }
function validateFilterOptionsRequired(conditions: any, path: string): string[] {
const errors: string[] = [];
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: [string, string][] = [
['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: any, path: string): string[] {
const errors: string[] = [];
if (!conditions?.conditions || !Array.isArray(conditions.conditions)) return errors;
conditions.conditions.forEach((condition: any, i: number) => {
errors.push(...validateOperatorStructure(
condition.operator,
`${path}.conditions[${i}].operator`
));
});
return errors;
}
/** @deprecated Use validateConditionNodeStructure instead */
export function validateFilterBasedNodeMetadata(node: WorkflowNode): string[] {
return validateConditionNodeStructure(node);
}
/** /**
* Validate operator structure * Validate operator structure
* Ensures operator has correct format: {type, operation, singleValue?} * Ensures operator has correct format: {type, operation, singleValue?}

View File

@@ -1713,12 +1713,16 @@ export class NodeSpecificValidators {
// Validate mode-specific requirements // Validate mode-specific requirements
if (config.mode === 'manual') { if (config.mode === 'manual') {
// In manual mode, at least one field should be defined // In manual mode, at least one field should be defined
const hasFields = config.values && Object.keys(config.values).length > 0; const hasFieldsViaValues = config.values && Object.keys(config.values).length > 0;
const hasFieldsViaAssignments = config.assignments?.assignments
&& Array.isArray(config.assignments.assignments)
&& config.assignments.assignments.length > 0;
const hasFields = hasFieldsViaValues || hasFieldsViaAssignments;
if (!hasFields && !config.jsonOutput) { if (!hasFields && !config.jsonOutput) {
warnings.push({ warnings.push({
type: 'missing_common', type: 'missing_common',
message: 'Set node has no fields configured - will output empty items', message: 'Set node has no fields configured - will output empty items',
suggestion: 'Add fields in the Values section or use JSON mode' suggestion: 'Add field assignments or use JSON mode'
}); });
} }
} }

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