mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-03-26 20:23:08 +00:00
Compare commits
8 Commits
v2.40.5
...
update/n8n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e49013d72 | ||
|
|
af2cfec668 | ||
|
|
ab2dc9824e | ||
|
|
657d5ab60c | ||
|
|
7e314f8ff2 | ||
|
|
3cc09b4f07 | ||
|
|
537e701610 | ||
|
|
a571ad5ef5 |
6
.github/workflows/dependency-check.yml
vendored
6
.github/workflows/dependency-check.yml
vendored
@@ -77,15 +77,15 @@ jobs:
|
|||||||
echo "Zod version: $ZOD_VERSION"
|
echo "Zod version: $ZOD_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Check MCP SDK version - must be exactly 1.27.1
|
# Check MCP SDK version - must be exactly 1.28.0
|
||||||
if [[ "$SDK_VERSION" == "not found" ]]; then
|
if [[ "$SDK_VERSION" == "not found" ]]; then
|
||||||
echo "❌ FAILED: Could not determine MCP SDK version!"
|
echo "❌ FAILED: Could not determine MCP SDK version!"
|
||||||
echo " The dependency may not have been installed correctly."
|
echo " The dependency may not have been installed correctly."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ "$SDK_VERSION" != "1.27.1" ]]; then
|
if [[ "$SDK_VERSION" != "1.28.0" ]]; then
|
||||||
echo "❌ FAILED: MCP SDK version mismatch!"
|
echo "❌ FAILED: MCP SDK version mismatch!"
|
||||||
echo " Expected: 1.27.1"
|
echo " Expected: 1.28.0"
|
||||||
echo " Got: $SDK_VERSION"
|
echo " Got: $SDK_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
echo "This can cause runtime errors. See issues #440, #444, #446, #447, #450"
|
echo "This can cause runtime errors. See issues #440, #444, #446, #447, #450"
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2.41.0] - 2026-03-25
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Updated n8n dependencies**: n8n 2.12.3 → 2.13.3, n8n-core 2.12.0 → 2.13.1, n8n-workflow 2.12.0 → 2.13.1, @n8n/n8n-nodes-langchain 2.12.0 → 2.13.1
|
||||||
|
- **Rebuilt node database**: 1,396 nodes (812 from n8n-nodes-base/langchain + 584 community: 516 verified + 68 npm)
|
||||||
|
- **Refreshed community nodes**: 584 total (up from 430), with 581 AI-generated documentation summaries
|
||||||
|
- **Improved documentation generator**: Strip `<think>` tags from thinking-model responses; use raw fetch for vLLM `chat_template_kwargs` support
|
||||||
|
- **Incremental community node updates**: `fetch:community` now upserts by default, preserving existing READMEs and AI summaries. Use `--rebuild` for clean slate
|
||||||
|
|
||||||
|
Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en
|
||||||
|
|
||||||
## [2.40.5] - 2026-03-22
|
## [2.40.5] - 2026-03-22
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
# n8n Update Process - Quick Reference
|
# n8n Update Process - Quick Reference
|
||||||
|
|
||||||
## ⚡ Recommended Fast Workflow (2025-11-04)
|
## ⚡ Recommended Fast Workflow (2026-03-25)
|
||||||
|
|
||||||
**CRITICAL FIRST STEP**: Check existing releases to avoid version conflicts!
|
**CRITICAL FIRST STEP**: Check existing releases to avoid version conflicts!
|
||||||
|
|
||||||
|
**IMPORTANT: Community nodes are preserved incrementally!**
|
||||||
|
- `npm run update:n8n` rebuilds the base node DB (wipes community nodes temporarily)
|
||||||
|
- Community nodes must be backed up BEFORE and restored AFTER the base rebuild
|
||||||
|
- `npm run fetch:community` now upserts by default (preserves READMEs + AI summaries)
|
||||||
|
- `npm run generate:docs:incremental` only processes nodes missing docs
|
||||||
|
- Use `generate:docs:readme-only` first, then `generate:docs:summary-only` with a local LLM
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. CHECK EXISTING RELEASES FIRST (prevents version conflicts!)
|
# 1. CHECK EXISTING RELEASES FIRST (prevents version conflicts!)
|
||||||
gh release list | head -5
|
gh release list | head -5
|
||||||
@@ -15,14 +22,29 @@ git checkout main && git pull
|
|||||||
# 3. Check for updates (dry run)
|
# 3. Check for updates (dry run)
|
||||||
npm run update:n8n:check
|
npm run update:n8n:check
|
||||||
|
|
||||||
# 4. Run update and skip tests (we'll test in CI)
|
# 4. Back up community nodes BEFORE update (update:n8n rebuilds base DB!)
|
||||||
|
sqlite3 data/nodes.db ".mode insert nodes" "SELECT * FROM nodes WHERE is_community = 1;" > /tmp/n8n_community_backup.sql
|
||||||
|
|
||||||
|
# 5. Run update and skip tests (we'll test in CI)
|
||||||
yes y | npm run update:n8n
|
yes y | npm run update:n8n
|
||||||
|
|
||||||
# 5. Refresh community nodes (standard practice!)
|
# 6. Restore community nodes after rebuild
|
||||||
npm run fetch:community
|
sqlite3 data/nodes.db < /tmp/n8n_community_backup.sql
|
||||||
npm run generate:docs
|
|
||||||
|
|
||||||
# 6. Create feature branch
|
# 7. Refresh community nodes (upserts - preserves existing READMEs + AI summaries!)
|
||||||
|
npm run fetch:community
|
||||||
|
# NOTE: Default mode is now "upsert" - no deletion. Use --rebuild for clean slate.
|
||||||
|
|
||||||
|
# 8. Generate docs incrementally (only for new/missing nodes)
|
||||||
|
npm run generate:docs:readme-only # Fetch READMEs from npm (no LLM needed)
|
||||||
|
# Then with a local LLM server running (LM Studio, vLLM, Ollama):
|
||||||
|
N8N_MCP_LLM_BASE_URL="http://YOUR_SERVER:PORT/v1" \
|
||||||
|
N8N_MCP_LLM_MODEL="your-model-name" \
|
||||||
|
node dist/scripts/generate-community-docs.js --summary-only --skip-existing-summary --llm-concurrency=11
|
||||||
|
# For vLLM with thinking models, the code auto-sends chat_template_kwargs: {enable_thinking: false}
|
||||||
|
# Context length needed: 8K minimum (README truncated to 6000 chars, output max 2000 tokens)
|
||||||
|
|
||||||
|
# 9. Create feature branch
|
||||||
git checkout -b update/n8n-X.X.X
|
git checkout -b update/n8n-X.X.X
|
||||||
|
|
||||||
# 7. Update version in package.json (must be HIGHER than latest release!)
|
# 7. Update version in package.json (must be HIGHER than latest release!)
|
||||||
|
|||||||
@@ -5,17 +5,17 @@
|
|||||||
[](https://www.npmjs.com/package/n8n-mcp)
|
[](https://www.npmjs.com/package/n8n-mcp)
|
||||||
[](https://codecov.io/gh/czlonkowski/n8n-mcp)
|
[](https://codecov.io/gh/czlonkowski/n8n-mcp)
|
||||||
[](https://github.com/czlonkowski/n8n-mcp/actions)
|
[](https://github.com/czlonkowski/n8n-mcp/actions)
|
||||||
[](https://github.com/n8n-io/n8n)
|
[](https://github.com/n8n-io/n8n)
|
||||||
[](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
[](https://github.com/czlonkowski/n8n-mcp/pkgs/container/n8n-mcp)
|
||||||
[](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
|
[](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp)
|
||||||
|
|
||||||
A Model Context Protocol (MCP) server that provides AI assistants with comprehensive access to n8n node documentation, properties, and operations. Deploy in minutes to give Claude and other AI assistants deep knowledge about n8n's 1,239 workflow automation nodes (809 core + 430 community).
|
A Model Context Protocol (MCP) server that provides AI assistants with comprehensive access to n8n node documentation, properties, and operations. Deploy in minutes to give Claude and other AI assistants deep knowledge about n8n's 1,396 workflow automation nodes (812 core + 584 community).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
n8n-MCP serves as a bridge between n8n's workflow automation platform and AI models, enabling them to understand and work with n8n nodes effectively. It provides structured access to:
|
n8n-MCP serves as a bridge between n8n's workflow automation platform and AI models, enabling them to understand and work with n8n nodes effectively. It provides structured access to:
|
||||||
|
|
||||||
- 📚 **1,084 n8n nodes** - 537 core nodes + 547 community nodes (301 verified)
|
- 📚 **1,396 n8n nodes** - 812 core nodes + 584 community nodes (516 verified)
|
||||||
- 🔧 **Node properties** - 99% coverage with detailed schemas
|
- 🔧 **Node properties** - 99% coverage with detailed schemas
|
||||||
- ⚡ **Node operations** - 63.6% coverage of available actions
|
- ⚡ **Node operations** - 63.6% coverage of available actions
|
||||||
- 📄 **Documentation** - 87% coverage from official n8n docs (including AI nodes)
|
- 📄 **Documentation** - 87% coverage from official n8n docs (including AI nodes)
|
||||||
|
|||||||
BIN
data/nodes.db
BIN
data/nodes.db
Binary file not shown.
2
dist/database/node-repository.d.ts.map
vendored
2
dist/database/node-repository.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"node-repository.d.ts","sourceRoot":"","sources":["../../src/database/node-repository.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"node-repository.d.ts","sourceRoot":"","sources":["../../src/database/node-repository.ts"],"names":[],"mappings":"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"}
|
||||||
31
dist/database/node-repository.js
vendored
31
dist/database/node-repository.js
vendored
@@ -13,7 +13,7 @@ class NodeRepository {
|
|||||||
}
|
}
|
||||||
saveNode(node) {
|
saveNode(node) {
|
||||||
const stmt = this.db.prepare(`
|
const stmt = this.db.prepare(`
|
||||||
INSERT OR REPLACE INTO nodes (
|
INSERT INTO nodes (
|
||||||
node_type, package_name, display_name, description,
|
node_type, package_name, display_name, description,
|
||||||
category, development_style, is_ai_tool, is_trigger,
|
category, development_style, is_ai_tool, is_trigger,
|
||||||
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
|
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
|
||||||
@@ -23,6 +23,35 @@ class NodeRepository {
|
|||||||
is_community, is_verified, author_name, author_github_url,
|
is_community, is_verified, author_name, author_github_url,
|
||||||
npm_package_name, npm_version, npm_downloads, community_fetched_at
|
npm_package_name, npm_version, npm_downloads, community_fetched_at
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
ON CONFLICT(node_type) DO UPDATE SET
|
||||||
|
package_name = excluded.package_name,
|
||||||
|
display_name = excluded.display_name,
|
||||||
|
description = excluded.description,
|
||||||
|
category = excluded.category,
|
||||||
|
development_style = excluded.development_style,
|
||||||
|
is_ai_tool = excluded.is_ai_tool,
|
||||||
|
is_trigger = excluded.is_trigger,
|
||||||
|
is_webhook = excluded.is_webhook,
|
||||||
|
is_versioned = excluded.is_versioned,
|
||||||
|
is_tool_variant = excluded.is_tool_variant,
|
||||||
|
tool_variant_of = excluded.tool_variant_of,
|
||||||
|
has_tool_variant = excluded.has_tool_variant,
|
||||||
|
version = excluded.version,
|
||||||
|
documentation = excluded.documentation,
|
||||||
|
properties_schema = excluded.properties_schema,
|
||||||
|
operations = excluded.operations,
|
||||||
|
credentials_required = excluded.credentials_required,
|
||||||
|
outputs = excluded.outputs,
|
||||||
|
output_names = excluded.output_names,
|
||||||
|
is_community = excluded.is_community,
|
||||||
|
is_verified = excluded.is_verified,
|
||||||
|
author_name = excluded.author_name,
|
||||||
|
author_github_url = excluded.author_github_url,
|
||||||
|
npm_package_name = excluded.npm_package_name,
|
||||||
|
npm_version = excluded.npm_version,
|
||||||
|
npm_downloads = excluded.npm_downloads,
|
||||||
|
community_fetched_at = excluded.community_fetched_at,
|
||||||
|
updated_at = CURRENT_TIMESTAMP
|
||||||
`);
|
`);
|
||||||
stmt.run(node.nodeType, node.packageName, node.displayName, node.description, node.category, node.style, node.isAITool ? 1 : 0, node.isTrigger ? 1 : 0, node.isWebhook ? 1 : 0, node.isVersioned ? 1 : 0, node.isToolVariant ? 1 : 0, node.toolVariantOf || null, node.hasToolVariant ? 1 : 0, node.version, node.documentation || null, JSON.stringify(node.properties, null, 2), JSON.stringify(node.operations, null, 2), JSON.stringify(node.credentials, null, 2), node.outputs ? JSON.stringify(node.outputs, null, 2) : null, node.outputNames ? JSON.stringify(node.outputNames, null, 2) : null, node.isCommunity ? 1 : 0, node.isVerified ? 1 : 0, node.authorName || null, node.authorGithubUrl || null, node.npmPackageName || null, node.npmVersion || null, node.npmDownloads || 0, node.communityFetchedAt || null);
|
stmt.run(node.nodeType, node.packageName, node.displayName, node.description, node.category, node.style, node.isAITool ? 1 : 0, node.isTrigger ? 1 : 0, node.isWebhook ? 1 : 0, node.isVersioned ? 1 : 0, node.isToolVariant ? 1 : 0, node.toolVariantOf || null, node.hasToolVariant ? 1 : 0, node.version, node.documentation || null, JSON.stringify(node.properties, null, 2), JSON.stringify(node.operations, null, 2), JSON.stringify(node.credentials, null, 2), node.outputs ? JSON.stringify(node.outputs, null, 2) : null, node.outputNames ? JSON.stringify(node.outputNames, null, 2) : null, node.isCommunity ? 1 : 0, node.isVerified ? 1 : 0, node.authorName || null, node.authorGithubUrl || null, node.npmPackageName || null, node.npmVersion || null, node.npmDownloads || 0, node.communityFetchedAt || null);
|
||||||
}
|
}
|
||||||
|
|||||||
2
dist/database/node-repository.js.map
vendored
2
dist/database/node-repository.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/http-server-single-session.d.ts
vendored
1
dist/http-server-single-session.d.ts
vendored
@@ -21,6 +21,7 @@ export declare class SingleSessionHTTPServer {
|
|||||||
private getActiveSessionCount;
|
private getActiveSessionCount;
|
||||||
private canCreateSession;
|
private canCreateSession;
|
||||||
private isValidSessionId;
|
private isValidSessionId;
|
||||||
|
private isJsonRpcNotification;
|
||||||
private sanitizeErrorForClient;
|
private sanitizeErrorForClient;
|
||||||
private updateSessionAccess;
|
private updateSessionAccess;
|
||||||
private switchSessionContext;
|
private switchSessionContext;
|
||||||
|
|||||||
2
dist/http-server-single-session.d.ts.map
vendored
2
dist/http-server-single-session.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"http-server-single-session.d.ts","sourceRoot":"","sources":["../src/http-server-single-session.ts"],"names":[],"mappings":";AAMA,OAAO,OAAO,MAAM,SAAS,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAwErD,qBAAa,uBAAuB;IAElC,OAAO,CAAC,UAAU,CAA8D;IAChF,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,eAAe,CAAsE;IAC7F,OAAO,CAAC,eAAe,CAA4D;IACnF,OAAO,CAAC,kBAAkB,CAAyC;IACnE,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,aAAa,CAAM;IAI3B,OAAO,CAAC,cAAc,CAER;IACd,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAA+B;;IAcnD,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,sBAAsB;YAqChB,aAAa;IAuC3B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,gBAAgB;IASxB,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;YA0PF,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;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"}
|
||||||
31
dist/http-server-single-session.js
vendored
31
dist/http-server-single-session.js
vendored
@@ -133,6 +133,15 @@ class SingleSessionHTTPServer {
|
|||||||
isValidSessionId(sessionId) {
|
isValidSessionId(sessionId) {
|
||||||
return Boolean(sessionId && sessionId.length > 0);
|
return Boolean(sessionId && sessionId.length > 0);
|
||||||
}
|
}
|
||||||
|
isJsonRpcNotification(body) {
|
||||||
|
if (!body || typeof body !== 'object')
|
||||||
|
return false;
|
||||||
|
const isSingleNotification = (msg) => msg && typeof msg.method === 'string' && !('id' in msg);
|
||||||
|
if (Array.isArray(body)) {
|
||||||
|
return body.length > 0 && body.every(isSingleNotification);
|
||||||
|
}
|
||||||
|
return isSingleNotification(body);
|
||||||
|
}
|
||||||
sanitizeErrorForClient(error) {
|
sanitizeErrorForClient(error) {
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@@ -381,6 +390,20 @@ class SingleSessionHTTPServer {
|
|||||||
}
|
}
|
||||||
logger_1.logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
logger_1.logger.info('handleRequest: Reusing existing transport for session', { sessionId });
|
||||||
transport = this.transports[sessionId];
|
transport = this.transports[sessionId];
|
||||||
|
if (!transport) {
|
||||||
|
if (this.isJsonRpcNotification(req.body)) {
|
||||||
|
logger_1.logger.info('handleRequest: Session removed during lookup, accepting notification', { sessionId });
|
||||||
|
res.status(202).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger_1.logger.warn('handleRequest: Session removed between check and use (TOCTOU)', { sessionId });
|
||||||
|
res.status(400).json({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
error: { code: -32000, message: 'Bad Request: Session not found or expired' },
|
||||||
|
id: req.body?.id || null,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const isMultiTenantEnabled = process.env.ENABLE_MULTI_TENANT === 'true';
|
const isMultiTenantEnabled = process.env.ENABLE_MULTI_TENANT === 'true';
|
||||||
const sessionStrategy = process.env.MULTI_TENANT_SESSION_STRATEGY || 'instance';
|
const sessionStrategy = process.env.MULTI_TENANT_SESSION_STRATEGY || 'instance';
|
||||||
if (isMultiTenantEnabled && sessionStrategy === 'shared' && instanceContext) {
|
if (isMultiTenantEnabled && sessionStrategy === 'shared' && instanceContext) {
|
||||||
@@ -389,6 +412,14 @@ class SingleSessionHTTPServer {
|
|||||||
this.updateSessionAccess(sessionId);
|
this.updateSessionAccess(sessionId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (this.isJsonRpcNotification(req.body)) {
|
||||||
|
logger_1.logger.info('handleRequest: Accepting notification for stale/missing session', {
|
||||||
|
method: req.body?.method,
|
||||||
|
sessionId: sessionId || 'none',
|
||||||
|
});
|
||||||
|
res.status(202).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const errorDetails = {
|
const errorDetails = {
|
||||||
hasSessionId: !!sessionId,
|
hasSessionId: !!sessionId,
|
||||||
isInitialize: isInitialize,
|
isInitialize: isInitialize,
|
||||||
|
|||||||
2
dist/http-server-single-session.js.map
vendored
2
dist/http-server-single-session.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/mcp/handlers-n8n-manager.d.ts.map
vendored
2
dist/mcp/handlers-n8n-manager.d.ts.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}
|
{"version":3,"file":"handlers-n8n-manager.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers-n8n-manager.ts"],"names":[],"mappings":"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"}
|
||||||
5
dist/mcp/handlers-n8n-manager.js
vendored
5
dist/mcp/handlers-n8n-manager.js
vendored
@@ -2176,10 +2176,13 @@ async function handleUpdateTable(args, context) {
|
|||||||
const client = ensureApiConfigured(context);
|
const client = ensureApiConfigured(context);
|
||||||
const { tableId, name } = updateTableSchema.parse(args);
|
const { tableId, name } = updateTableSchema.parse(args);
|
||||||
const dataTable = await client.updateDataTable(tableId, { name });
|
const dataTable = await client.updateDataTable(tableId, { name });
|
||||||
|
const rawArgs = args;
|
||||||
|
const hasColumns = rawArgs && typeof rawArgs === 'object' && 'columns' in rawArgs;
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
message: `Data table renamed to "${dataTable.name}"`,
|
message: `Data table renamed to "${dataTable.name}"` +
|
||||||
|
(hasColumns ? '. Note: columns parameter was ignored — table schema is immutable after creation via the public API' : ''),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
|||||||
2
dist/mcp/handlers-n8n-manager.js.map
vendored
2
dist/mcp/handlers-n8n-manager.js.map
vendored
File diff suppressed because one or more lines are too long
6
dist/mcp/tools-n8n-manager.js
vendored
6
dist/mcp/tools-n8n-manager.js
vendored
@@ -590,7 +590,7 @@ exports.n8nManagementTools = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'n8n_manage_datatable',
|
name: 'n8n_manage_datatable',
|
||||||
description: `Manage n8n data tables and rows. Actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows. Requires n8n enterprise/cloud with data tables feature.`,
|
description: `Manage n8n data tables and rows. Actions: createTable, listTables, getTable, updateTable, deleteTable, getRows, insertRows, updateRows, upsertRows, deleteRows.`,
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@@ -600,10 +600,10 @@ exports.n8nManagementTools = [
|
|||||||
description: 'Operation to perform',
|
description: 'Operation to perform',
|
||||||
},
|
},
|
||||||
tableId: { type: 'string', description: 'Data table ID (required for all actions except createTable and listTables)' },
|
tableId: { type: 'string', description: 'Data table ID (required for all actions except createTable and listTables)' },
|
||||||
name: { type: 'string', description: 'For createTable/updateTable: table name' },
|
name: { type: 'string', description: 'For createTable: table name. For updateTable: new name (rename only — schema is immutable after creation)' },
|
||||||
columns: {
|
columns: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
description: 'For createTable: column definitions',
|
description: 'For createTable only: column definitions (schema is immutable after creation via public API)',
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|||||||
2
dist/mcp/tools-n8n-manager.js.map
vendored
2
dist/mcp/tools-n8n-manager.js.map
vendored
File diff suppressed because one or more lines are too long
9017
package-lock.json
generated
9017
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "n8n-mcp",
|
"name": "n8n-mcp",
|
||||||
"version": "2.40.5",
|
"version": "2.41.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",
|
||||||
@@ -152,17 +152,17 @@
|
|||||||
"vitest": "^3.2.4"
|
"vitest": "^3.2.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.27.1",
|
"@modelcontextprotocol/sdk": "1.28.0",
|
||||||
"@n8n/n8n-nodes-langchain": "^2.12.0",
|
"@n8n/n8n-nodes-langchain": "^2.13.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.12.3",
|
"n8n": "^2.13.3",
|
||||||
"n8n-core": "^2.12.0",
|
"n8n-core": "^2.13.1",
|
||||||
"n8n-workflow": "^2.12.0",
|
"n8n-workflow": "^2.13.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",
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ const DEFAULT_CONFIG: Required<Omit<DocumentationGeneratorConfig, 'baseUrl' | 't
|
|||||||
*/
|
*/
|
||||||
export class DocumentationGenerator {
|
export class DocumentationGenerator {
|
||||||
private client: OpenAI;
|
private client: OpenAI;
|
||||||
|
private baseUrl: string;
|
||||||
|
private apiKey: string;
|
||||||
private model: string;
|
private model: string;
|
||||||
private maxTokens: number;
|
private maxTokens: number;
|
||||||
private timeout: number;
|
private timeout: number;
|
||||||
@@ -85,6 +87,8 @@ export class DocumentationGenerator {
|
|||||||
constructor(config: DocumentationGeneratorConfig) {
|
constructor(config: DocumentationGeneratorConfig) {
|
||||||
const fullConfig = { ...DEFAULT_CONFIG, ...config };
|
const fullConfig = { ...DEFAULT_CONFIG, ...config };
|
||||||
|
|
||||||
|
this.baseUrl = config.baseUrl;
|
||||||
|
this.apiKey = fullConfig.apiKey;
|
||||||
this.client = new OpenAI({
|
this.client = new OpenAI({
|
||||||
baseURL: config.baseUrl,
|
baseURL: config.baseUrl,
|
||||||
apiKey: fullConfig.apiKey,
|
apiKey: fullConfig.apiKey,
|
||||||
@@ -103,21 +107,10 @@ export class DocumentationGenerator {
|
|||||||
try {
|
try {
|
||||||
const prompt = this.buildPrompt(input);
|
const prompt = this.buildPrompt(input);
|
||||||
|
|
||||||
const completion = await this.client.chat.completions.create({
|
const completion = await this.chatCompletion([
|
||||||
model: this.model,
|
{ role: 'system', content: this.getSystemPrompt() },
|
||||||
max_completion_tokens: this.maxTokens,
|
{ role: 'user', content: prompt },
|
||||||
...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
|
], this.maxTokens);
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content: this.getSystemPrompt(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: prompt,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const content = completion.choices[0]?.message?.content;
|
const content = completion.choices[0]?.message?.content;
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@@ -246,20 +239,23 @@ Guidelines:
|
|||||||
* Extract JSON from LLM response (handles markdown code blocks)
|
* Extract JSON from LLM response (handles markdown code blocks)
|
||||||
*/
|
*/
|
||||||
private extractJson(content: string): string {
|
private extractJson(content: string): string {
|
||||||
|
// Strip <think>...</think> blocks from thinking models (e.g., Qwen3-Thinking)
|
||||||
|
const stripped = content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
||||||
|
|
||||||
// Try to extract from markdown code block
|
// Try to extract from markdown code block
|
||||||
const jsonBlockMatch = content.match(/```(?:json)?\s*([\s\S]*?)```/);
|
const jsonBlockMatch = stripped.match(/```(?:json)?\s*([\s\S]*?)```/);
|
||||||
if (jsonBlockMatch) {
|
if (jsonBlockMatch) {
|
||||||
return jsonBlockMatch[1].trim();
|
return jsonBlockMatch[1].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find JSON object directly
|
// Try to find JSON object directly
|
||||||
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
const jsonMatch = stripped.match(/\{[\s\S]*\}/);
|
||||||
if (jsonMatch) {
|
if (jsonMatch) {
|
||||||
return jsonMatch[0];
|
return jsonMatch[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return as-is if no extraction needed
|
// Return as-is if no extraction needed
|
||||||
return content.trim();
|
return stripped;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -323,16 +319,9 @@ Guidelines:
|
|||||||
*/
|
*/
|
||||||
async testConnection(): Promise<{ success: boolean; message: string }> {
|
async testConnection(): Promise<{ success: boolean; message: string }> {
|
||||||
try {
|
try {
|
||||||
const completion = await this.client.chat.completions.create({
|
const completion = await this.chatCompletion([
|
||||||
model: this.model,
|
{ role: 'user', content: 'Hello' },
|
||||||
max_completion_tokens: 200,
|
], 200);
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: 'Hello',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (completion.choices[0]?.message?.content) {
|
if (completion.choices[0]?.message?.content) {
|
||||||
return { success: true, message: `Connected to ${this.model}` };
|
return { success: true, message: `Connected to ${this.model}` };
|
||||||
@@ -345,6 +334,44 @@ Guidelines:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a chat completion request with chat_template_kwargs support for vLLM thinking models
|
||||||
|
*/
|
||||||
|
private async chatCompletion(
|
||||||
|
messages: Array<{ role: string; content: string }>,
|
||||||
|
maxTokens: number
|
||||||
|
): Promise<{ choices: Array<{ message: { content: string | null } }> }> {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(this.apiKey !== 'not-needed' ? { Authorization: `Bearer ${this.apiKey}` } : {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: this.model,
|
||||||
|
messages,
|
||||||
|
max_completion_tokens: maxTokens,
|
||||||
|
...(this.temperature !== undefined ? { temperature: this.temperature } : {}),
|
||||||
|
chat_template_kwargs: { enable_thinking: false },
|
||||||
|
}),
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const text = await response.text();
|
||||||
|
throw new Error(`${response.status} ${text}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await response.json()) as { choices: Array<{ message: { content: string | null } }> };
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private sleep(ms: number): Promise<void> {
|
private sleep(ms: number): Promise<void> {
|
||||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ export class NodeRepository {
|
|||||||
* Supports both core and community nodes via optional community fields
|
* Supports both core and community nodes via optional community fields
|
||||||
*/
|
*/
|
||||||
saveNode(node: ParsedNode & Partial<CommunityNodeFields>): void {
|
saveNode(node: ParsedNode & Partial<CommunityNodeFields>): void {
|
||||||
|
// Preserve existing npm_readme and ai_documentation_summary on upsert
|
||||||
|
const existing = this.db.prepare(
|
||||||
|
'SELECT npm_readme, ai_documentation_summary, ai_summary_generated_at FROM nodes WHERE node_type = ?'
|
||||||
|
).get(node.nodeType) as { npm_readme?: string; ai_documentation_summary?: string; ai_summary_generated_at?: string } | undefined;
|
||||||
|
|
||||||
const stmt = this.db.prepare(`
|
const stmt = this.db.prepare(`
|
||||||
INSERT OR REPLACE INTO nodes (
|
INSERT OR REPLACE INTO nodes (
|
||||||
node_type, package_name, display_name, description,
|
node_type, package_name, display_name, description,
|
||||||
@@ -43,8 +48,9 @@ export class NodeRepository {
|
|||||||
properties_schema, operations, credentials_required,
|
properties_schema, operations, credentials_required,
|
||||||
outputs, output_names,
|
outputs, output_names,
|
||||||
is_community, is_verified, author_name, author_github_url,
|
is_community, is_verified, author_name, author_github_url,
|
||||||
npm_package_name, npm_version, npm_downloads, community_fetched_at
|
npm_package_name, npm_version, npm_downloads, community_fetched_at,
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
npm_readme, ai_documentation_summary, ai_summary_generated_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
stmt.run(
|
stmt.run(
|
||||||
@@ -76,7 +82,11 @@ export class NodeRepository {
|
|||||||
node.npmPackageName || null,
|
node.npmPackageName || null,
|
||||||
node.npmVersion || null,
|
node.npmVersion || null,
|
||||||
node.npmDownloads || 0,
|
node.npmDownloads || 0,
|
||||||
node.communityFetchedAt || null
|
node.communityFetchedAt || null,
|
||||||
|
// Preserve existing docs data on upsert
|
||||||
|
existing?.npm_readme || null,
|
||||||
|
existing?.ai_documentation_summary || null,
|
||||||
|
existing?.ai_summary_generated_at || null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
* Fetch community nodes from n8n Strapi API and npm registry.
|
* Fetch community nodes from n8n Strapi API and npm registry.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* npm run fetch:community # Full rebuild (verified + top 100 npm)
|
* npm run fetch:community # Upsert all (preserves READMEs and AI summaries)
|
||||||
* npm run fetch:community:verified # Verified nodes only (fast)
|
* npm run fetch:community:verified # Verified nodes only (fast)
|
||||||
* npm run fetch:community:update # Incremental update (skip existing)
|
* npm run fetch:community:update # Incremental update (skip existing)
|
||||||
*
|
*
|
||||||
* Options:
|
* Options:
|
||||||
* --verified-only Only fetch verified nodes from Strapi API
|
* --verified-only Only fetch verified nodes from Strapi API
|
||||||
* --update Skip nodes that already exist in database
|
* --update Skip nodes that already exist in database
|
||||||
|
* --rebuild Delete all community nodes first (wipes READMEs/AI summaries!)
|
||||||
* --npm-limit=N Maximum number of npm packages to fetch (default: 100)
|
* --npm-limit=N Maximum number of npm packages to fetch (default: 100)
|
||||||
* --staging Use staging Strapi API instead of production
|
* --staging Use staging Strapi API instead of production
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +23,7 @@ import { createDatabaseAdapter } from '../database/database-adapter';
|
|||||||
interface CliOptions {
|
interface CliOptions {
|
||||||
verifiedOnly: boolean;
|
verifiedOnly: boolean;
|
||||||
update: boolean;
|
update: boolean;
|
||||||
|
rebuild: boolean;
|
||||||
npmLimit: number;
|
npmLimit: number;
|
||||||
staging: boolean;
|
staging: boolean;
|
||||||
}
|
}
|
||||||
@@ -32,6 +34,7 @@ function parseArgs(): CliOptions {
|
|||||||
const options: CliOptions = {
|
const options: CliOptions = {
|
||||||
verifiedOnly: false,
|
verifiedOnly: false,
|
||||||
update: false,
|
update: false,
|
||||||
|
rebuild: false,
|
||||||
npmLimit: 100,
|
npmLimit: 100,
|
||||||
staging: false,
|
staging: false,
|
||||||
};
|
};
|
||||||
@@ -41,6 +44,8 @@ function parseArgs(): CliOptions {
|
|||||||
options.verifiedOnly = true;
|
options.verifiedOnly = true;
|
||||||
} else if (arg === '--update') {
|
} else if (arg === '--update') {
|
||||||
options.update = true;
|
options.update = true;
|
||||||
|
} else if (arg === '--rebuild') {
|
||||||
|
options.rebuild = true;
|
||||||
} else if (arg === '--staging') {
|
} else if (arg === '--staging') {
|
||||||
options.staging = true;
|
options.staging = true;
|
||||||
} else if (arg.startsWith('--npm-limit=')) {
|
} else if (arg.startsWith('--npm-limit=')) {
|
||||||
@@ -73,7 +78,7 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
// Print options
|
// Print options
|
||||||
console.log('Options:');
|
console.log('Options:');
|
||||||
console.log(` - Mode: ${cliOptions.update ? 'Update (incremental)' : 'Rebuild'}`);
|
console.log(` - Mode: ${cliOptions.rebuild ? 'Rebuild (clean slate)' : cliOptions.update ? 'Update (skip existing)' : 'Upsert (preserves docs)'}`);
|
||||||
console.log(` - Verified only: ${cliOptions.verifiedOnly ? 'Yes' : 'No'}`);
|
console.log(` - Verified only: ${cliOptions.verifiedOnly ? 'Yes' : 'No'}`);
|
||||||
if (!cliOptions.verifiedOnly) {
|
if (!cliOptions.verifiedOnly) {
|
||||||
console.log(` - npm package limit: ${cliOptions.npmLimit}`);
|
console.log(` - npm package limit: ${cliOptions.npmLimit}`);
|
||||||
@@ -92,9 +97,10 @@ async function main(): Promise<void> {
|
|||||||
const environment = cliOptions.staging ? 'staging' : 'production';
|
const environment = cliOptions.staging ? 'staging' : 'production';
|
||||||
const service = new CommunityNodeService(repository, environment);
|
const service = new CommunityNodeService(repository, environment);
|
||||||
|
|
||||||
// If not updating, delete existing community nodes
|
// Only delete existing community nodes when --rebuild is explicitly requested
|
||||||
if (!cliOptions.update) {
|
if (cliOptions.rebuild) {
|
||||||
console.log('\nClearing existing community nodes...');
|
console.log('\nClearing existing community nodes (--rebuild)...');
|
||||||
|
console.log(' WARNING: This wipes READMEs and AI summaries!');
|
||||||
const deleted = service.deleteCommunityNodes();
|
const deleted = service.deleteCommunityNodes();
|
||||||
console.log(` Deleted ${deleted} existing community nodes`);
|
console.log(` Deleted ${deleted} existing community nodes`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class InMemoryDatabaseAdapter implements DatabaseAdapter {
|
|||||||
|
|
||||||
class InMemoryPreparedStatement implements PreparedStatement {
|
class InMemoryPreparedStatement implements PreparedStatement {
|
||||||
run = vi.fn((...params: any[]): RunResult => {
|
run = vi.fn((...params: any[]): RunResult => {
|
||||||
if (this.sql.includes('INSERT OR REPLACE INTO nodes')) {
|
if (this.sql.includes('INSERT') && this.sql.includes('INTO nodes')) {
|
||||||
const node = this.paramsToNode(params);
|
const node = this.paramsToNode(params);
|
||||||
this.adapter.saveNode(node);
|
this.adapter.saveNode(node);
|
||||||
return { changes: 1, lastInsertRowid: 1 };
|
return { changes: 1, lastInsertRowid: 1 };
|
||||||
@@ -100,6 +100,9 @@ class InMemoryPreparedStatement implements PreparedStatement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
get = vi.fn((...params: any[]) => {
|
get = vi.fn((...params: any[]) => {
|
||||||
|
if (this.sql.includes('SELECT npm_readme')) {
|
||||||
|
return undefined; // No existing docs to preserve
|
||||||
|
}
|
||||||
if (this.sql.includes('SELECT * FROM nodes WHERE node_type = ?')) {
|
if (this.sql.includes('SELECT * FROM nodes WHERE node_type = ?')) {
|
||||||
return this.adapter.getNode(params[0]);
|
return this.adapter.getNode(params[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
115
tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts
Normal file
115
tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env tsx
|
||||||
|
/**
|
||||||
|
* Cleanup Non-Test Workflows
|
||||||
|
*
|
||||||
|
* Deletes all workflows from the n8n test instance EXCEPT those
|
||||||
|
* with "[TEST]" in the name. This helps keep the test instance
|
||||||
|
* clean and prevents list endpoint pagination issues.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* npx tsx tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts
|
||||||
|
* npx tsx tests/integration/n8n-api/scripts/cleanup-non-test-workflows.ts --dry-run
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getN8nCredentials, validateCredentials } from '../utils/credentials';
|
||||||
|
|
||||||
|
const DRY_RUN = process.argv.includes('--dry-run');
|
||||||
|
|
||||||
|
interface Workflow {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAllWorkflows(baseUrl: string, apiKey: string): Promise<Workflow[]> {
|
||||||
|
const all: Workflow[] = [];
|
||||||
|
let cursor: string | undefined;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const url = new URL('/api/v1/workflows', baseUrl);
|
||||||
|
url.searchParams.set('limit', '100');
|
||||||
|
if (cursor) url.searchParams.set('cursor', cursor);
|
||||||
|
|
||||||
|
const res = await fetch(url.toString(), {
|
||||||
|
headers: { 'X-N8N-API-KEY': apiKey }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Failed to list workflows: ${res.status} ${res.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await res.json() as { data: Workflow[]; nextCursor?: string };
|
||||||
|
all.push(...body.data);
|
||||||
|
|
||||||
|
if (!body.nextCursor) break;
|
||||||
|
cursor = body.nextCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteWorkflow(baseUrl: string, apiKey: string, id: string): Promise<void> {
|
||||||
|
const res = await fetch(`${baseUrl}/api/v1/workflows/${id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: { 'X-N8N-API-KEY': apiKey }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Failed to delete workflow ${id}: ${res.status} ${res.statusText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const creds = getN8nCredentials();
|
||||||
|
validateCredentials(creds);
|
||||||
|
|
||||||
|
console.log(`n8n Instance: ${creds.url}`);
|
||||||
|
console.log(`Mode: ${DRY_RUN ? 'DRY RUN' : 'LIVE DELETE'}\n`);
|
||||||
|
|
||||||
|
const workflows = await fetchAllWorkflows(creds.url, creds.apiKey);
|
||||||
|
console.log(`Total workflows found: ${workflows.length}\n`);
|
||||||
|
|
||||||
|
const toKeep = workflows.filter(w => w.name.includes('[TEST]'));
|
||||||
|
const toDelete = workflows.filter(w => !w.name.includes('[TEST]'));
|
||||||
|
|
||||||
|
console.log(`Keeping (${toKeep.length}):`);
|
||||||
|
for (const w of toKeep) {
|
||||||
|
console.log(` ✅ ${w.id} - ${w.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDeleting (${toDelete.length}):`);
|
||||||
|
for (const w of toDelete) {
|
||||||
|
console.log(` 🗑️ ${w.id} - ${w.name}${w.active ? ' (ACTIVE)' : ''}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DRY_RUN) {
|
||||||
|
console.log('\nDry run complete. No workflows were deleted.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toDelete.length === 0) {
|
||||||
|
console.log('\nNothing to delete.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDeleting ${toDelete.length} workflows...`);
|
||||||
|
let deleted = 0;
|
||||||
|
let failed = 0;
|
||||||
|
|
||||||
|
for (const w of toDelete) {
|
||||||
|
try {
|
||||||
|
await deleteWorkflow(creds.url, creds.apiKey, w.id);
|
||||||
|
deleted++;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(` Failed to delete ${w.id} (${w.name}): ${err}`);
|
||||||
|
failed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDone! Deleted: ${deleted}, Failed: ${failed}, Kept: ${toKeep.length}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error('Fatal error:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -119,6 +119,11 @@ class MockPreparedStatement implements PreparedStatement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// saveNode - SELECT existing doc fields before upsert
|
||||||
|
if (this.sql.includes('SELECT npm_readme, ai_documentation_summary, ai_summary_generated_at FROM nodes')) {
|
||||||
|
this.get = vi.fn(() => undefined); // No existing row by default
|
||||||
|
}
|
||||||
|
|
||||||
// saveNode - INSERT OR REPLACE
|
// saveNode - INSERT OR REPLACE
|
||||||
if (this.sql.includes('INSERT OR REPLACE INTO nodes')) {
|
if (this.sql.includes('INSERT OR REPLACE INTO nodes')) {
|
||||||
this.run = vi.fn((...params: any[]): RunResult => {
|
this.run = vi.fn((...params: any[]): RunResult => {
|
||||||
|
|||||||
@@ -49,7 +49,12 @@ class MockPreparedStatement implements PreparedStatement {
|
|||||||
if (sql.includes('SELECT * FROM nodes WHERE node_type = ?')) {
|
if (sql.includes('SELECT * FROM nodes WHERE node_type = ?')) {
|
||||||
this.get = vi.fn((nodeType: string) => this.mockData.get(`node:${nodeType}`));
|
this.get = vi.fn((nodeType: string) => this.mockData.get(`node:${nodeType}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure get() for saveNode's SELECT to preserve existing doc fields
|
||||||
|
if (sql.includes('SELECT npm_readme, ai_documentation_summary, ai_summary_generated_at FROM nodes')) {
|
||||||
|
this.get = vi.fn(() => undefined); // No existing row by default
|
||||||
|
}
|
||||||
|
|
||||||
// Configure all() for getAITools
|
// Configure all() for getAITools
|
||||||
if (sql.includes('WHERE is_ai_tool = 1')) {
|
if (sql.includes('WHERE is_ai_tool = 1')) {
|
||||||
this.all = vi.fn(() => this.mockData.get('ai_tools') || []);
|
this.all = vi.fn(() => this.mockData.get('ai_tools') || []);
|
||||||
@@ -123,7 +128,10 @@ describe('NodeRepository - Core Functionality', () => {
|
|||||||
null, // npmPackageName
|
null, // npmPackageName
|
||||||
null, // npmVersion
|
null, // npmVersion
|
||||||
0, // npmDownloads
|
0, // npmDownloads
|
||||||
null // communityFetchedAt
|
null, // communityFetchedAt
|
||||||
|
null, // npm_readme (preserved from existing)
|
||||||
|
null, // ai_documentation_summary (preserved from existing)
|
||||||
|
null // ai_summary_generated_at (preserved from existing)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,21 @@ describe('NodeRepository - Outputs Handling', () => {
|
|||||||
all: vi.fn()
|
all: vi.fn()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// saveNode now calls prepare twice: first a SELECT (returns get), then INSERT (returns run).
|
||||||
|
// We create a separate mock for the SELECT statement that returns undefined (no existing row).
|
||||||
|
const selectStatement = {
|
||||||
|
run: vi.fn(),
|
||||||
|
get: vi.fn().mockReturnValue(undefined),
|
||||||
|
all: vi.fn()
|
||||||
|
};
|
||||||
|
|
||||||
mockDb = {
|
mockDb = {
|
||||||
prepare: vi.fn().mockReturnValue(mockStatement),
|
prepare: vi.fn((sql: string) => {
|
||||||
|
if (sql.includes('SELECT npm_readme')) {
|
||||||
|
return selectStatement;
|
||||||
|
}
|
||||||
|
return mockStatement;
|
||||||
|
}),
|
||||||
transaction: vi.fn(),
|
transaction: vi.fn(),
|
||||||
exec: vi.fn(),
|
exec: vi.fn(),
|
||||||
close: vi.fn(),
|
close: vi.fn(),
|
||||||
@@ -55,18 +68,9 @@ describe('NodeRepository - Outputs Handling', () => {
|
|||||||
|
|
||||||
repository.saveNode(node);
|
repository.saveNode(node);
|
||||||
|
|
||||||
expect(mockDb.prepare).toHaveBeenCalledWith(`
|
expect(mockDb.prepare).toHaveBeenCalledWith(
|
||||||
INSERT OR REPLACE INTO nodes (
|
expect.stringContaining('INSERT OR REPLACE INTO nodes')
|
||||||
node_type, package_name, display_name, description,
|
);
|
||||||
category, development_style, is_ai_tool, is_trigger,
|
|
||||||
is_webhook, is_versioned, is_tool_variant, tool_variant_of,
|
|
||||||
has_tool_variant, version, documentation,
|
|
||||||
properties_schema, operations, credentials_required,
|
|
||||||
outputs, output_names,
|
|
||||||
is_community, is_verified, author_name, author_github_url,
|
|
||||||
npm_package_name, npm_version, npm_downloads, community_fetched_at
|
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
`);
|
|
||||||
|
|
||||||
expect(mockStatement.run).toHaveBeenCalledWith(
|
expect(mockStatement.run).toHaveBeenCalledWith(
|
||||||
'nodes-base.splitInBatches',
|
'nodes-base.splitInBatches',
|
||||||
@@ -96,7 +100,10 @@ describe('NodeRepository - Outputs Handling', () => {
|
|||||||
null, // npm_package_name
|
null, // npm_package_name
|
||||||
null, // npm_version
|
null, // npm_version
|
||||||
0, // npm_downloads
|
0, // npm_downloads
|
||||||
null // community_fetched_at
|
null, // community_fetched_at
|
||||||
|
null, // npm_readme (preserved from existing)
|
||||||
|
null, // ai_documentation_summary (preserved from existing)
|
||||||
|
null // ai_summary_generated_at (preserved from existing)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user