@path58/p58-n8n 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/mcp/server.bundle.cjs +218 -43
- package/package.json +1 -1
- package/src/data/public-catalog/credential-fields.json +1 -1209
- package/src/data/public-catalog/credentials.json +1 -679
- package/src/data/public-catalog/manifest.json +4 -4
- package/src/data/public-catalog/node-credentials.json +1 -4629
- package/src/data/public-catalog/nodes.json +1 -1545
- package/src/data/public-catalog/operations.json +1 -12619
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@path58/p58-n8n)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](https://github.com/tsvika58/p58-n8n/actions/workflows/ci.yml)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
|
|
10
10
|
p58-n8n is an MCP server that gives your AI assistant deep knowledge of n8n — **1,545 nodes**, **12,619 operations**, **679 credential types** — so it can plan, build, validate, fix, and deploy workflows correctly.
|
|
@@ -40771,6 +40771,16 @@ function extractCredentialNames(nodes) {
|
|
|
40771
40771
|
return [...new Set(names)];
|
|
40772
40772
|
}
|
|
40773
40773
|
async function testViaClone(workflow, triggerType, testPayload, timeoutMs, apiConfig) {
|
|
40774
|
+
const hasR2W = await hasRespondToWebhookNode(workflow);
|
|
40775
|
+
if (hasR2W) {
|
|
40776
|
+
return {
|
|
40777
|
+
execution_id: null,
|
|
40778
|
+
status: "error",
|
|
40779
|
+
trigger_type: triggerType,
|
|
40780
|
+
result_summary: "Cannot test via clone: workflow contains a Respond to Webhook node. Test this workflow using test_workflow with a direct webhook POST.",
|
|
40781
|
+
next_step: "This workflow has a Respond to Webhook node. Call test_workflow directly \u2014 it handles the response mode correctly."
|
|
40782
|
+
};
|
|
40783
|
+
}
|
|
40774
40784
|
const nodes = workflow.nodes ?? [];
|
|
40775
40785
|
const triggerNode = nodes.find((n) => {
|
|
40776
40786
|
const type = String(n?.type ?? "").toLowerCase();
|
|
@@ -40989,7 +40999,14 @@ async function fetchWorkflowWithTrigger(apiConfig, workflowId, timeoutMs) {
|
|
|
40989
40999
|
return { workflow, triggerType: await detectTriggerType(workflow) };
|
|
40990
41000
|
}
|
|
40991
41001
|
function buildTestSuccessResponse(result, correlationId, startTime) {
|
|
40992
|
-
|
|
41002
|
+
const isTestError = result.status === "error";
|
|
41003
|
+
const resultData = isTestError ? {
|
|
41004
|
+
success: false,
|
|
41005
|
+
...result,
|
|
41006
|
+
result_summary: result.result_summary.startsWith("\u274C") ? result.result_summary : `\u274C TEST FAILED: ${result.result_summary}`
|
|
41007
|
+
} : { success: true, ...result };
|
|
41008
|
+
const response = toMCPResponse(createSuccessResponse(resultData, correlationId, { duration_ms: Math.round(performance.now() - startTime) }));
|
|
41009
|
+
return isTestError ? { ...response, isError: true } : response;
|
|
40993
41010
|
}
|
|
40994
41011
|
async function executeTestWorkflow(args, correlationId, startTime) {
|
|
40995
41012
|
const workflowId = args.workflow_id;
|
|
@@ -48360,7 +48377,12 @@ var SERVICE_MAPPINGS = [
|
|
|
48360
48377
|
role: "action",
|
|
48361
48378
|
defaultOperation: "sendMessage",
|
|
48362
48379
|
defaultResource: "message",
|
|
48363
|
-
credentialType: "telegramApi"
|
|
48380
|
+
credentialType: "telegramApi",
|
|
48381
|
+
defaultParameters: {
|
|
48382
|
+
chatId: '={{ $json.chatId || $json.chat_id || "" }}',
|
|
48383
|
+
text: "={{ $json.text || $json.message || $json.output || JSON.stringify($json).substring(0, 500) }}",
|
|
48384
|
+
additionalFields: {}
|
|
48385
|
+
}
|
|
48364
48386
|
},
|
|
48365
48387
|
{
|
|
48366
48388
|
keywords: ["slack"],
|
|
@@ -48368,7 +48390,12 @@ var SERVICE_MAPPINGS = [
|
|
|
48368
48390
|
displayName: "Slack",
|
|
48369
48391
|
role: "action",
|
|
48370
48392
|
defaultOperation: "postMessage",
|
|
48371
|
-
credentialType: "slackApi"
|
|
48393
|
+
credentialType: "slackApi",
|
|
48394
|
+
defaultParameters: {
|
|
48395
|
+
channel: '={{ $json.channel || "" }}',
|
|
48396
|
+
text: "={{ $json.text || $json.message || $json.output || JSON.stringify($json).substring(0, 500) }}",
|
|
48397
|
+
select: "channel"
|
|
48398
|
+
}
|
|
48372
48399
|
},
|
|
48373
48400
|
{
|
|
48374
48401
|
keywords: ["gmail", "send email"],
|
|
@@ -48376,21 +48403,38 @@ var SERVICE_MAPPINGS = [
|
|
|
48376
48403
|
displayName: "Gmail",
|
|
48377
48404
|
role: "action",
|
|
48378
48405
|
defaultOperation: "send",
|
|
48379
|
-
|
|
48406
|
+
defaultResource: "message",
|
|
48407
|
+
credentialType: "gmailOAuth2",
|
|
48408
|
+
defaultParameters: {
|
|
48409
|
+
sendTo: '={{ $json.to || $json.email || "" }}',
|
|
48410
|
+
subject: '={{ $json.subject || "Notification" }}',
|
|
48411
|
+
message: "={{ $json.text || $json.body || $json.message || JSON.stringify($json).substring(0, 500) }}",
|
|
48412
|
+
options: {}
|
|
48413
|
+
}
|
|
48380
48414
|
},
|
|
48381
48415
|
{
|
|
48382
|
-
keywords: ["email", "smtp"],
|
|
48416
|
+
keywords: ["send email", "smtp", "email notification"],
|
|
48383
48417
|
nodeType: "n8n-nodes-base.emailSend",
|
|
48384
48418
|
displayName: "Send Email",
|
|
48385
48419
|
role: "action",
|
|
48386
|
-
credentialType: "smtp"
|
|
48420
|
+
credentialType: "smtp",
|
|
48421
|
+
defaultParameters: {
|
|
48422
|
+
fromEmail: '={{ $json.from || "" }}',
|
|
48423
|
+
toEmail: '={{ $json.to || $json.email || "" }}',
|
|
48424
|
+
subject: '={{ $json.subject || "Notification" }}',
|
|
48425
|
+
text: "={{ $json.text || $json.body || JSON.stringify($json).substring(0, 500) }}",
|
|
48426
|
+
options: {}
|
|
48427
|
+
}
|
|
48387
48428
|
},
|
|
48388
48429
|
{
|
|
48389
48430
|
keywords: ["discord"],
|
|
48390
48431
|
nodeType: "n8n-nodes-base.discord",
|
|
48391
48432
|
displayName: "Discord",
|
|
48392
48433
|
role: "action",
|
|
48393
|
-
credentialType: "discordApi"
|
|
48434
|
+
credentialType: "discordApi",
|
|
48435
|
+
defaultParameters: {
|
|
48436
|
+
content: "={{ $json.text || $json.message || JSON.stringify($json).substring(0, 500) }}"
|
|
48437
|
+
}
|
|
48394
48438
|
},
|
|
48395
48439
|
// ── Data & Storage ──
|
|
48396
48440
|
{
|
|
@@ -48398,14 +48442,15 @@ var SERVICE_MAPPINGS = [
|
|
|
48398
48442
|
nodeType: "n8n-nodes-base.notion",
|
|
48399
48443
|
displayName: "Notion",
|
|
48400
48444
|
role: "action",
|
|
48401
|
-
defaultOperation: "
|
|
48402
|
-
defaultResource: "
|
|
48445
|
+
defaultOperation: "getAll",
|
|
48446
|
+
defaultResource: "databasePage",
|
|
48403
48447
|
credentialType: "notionApi",
|
|
48404
48448
|
defaultParameters: {
|
|
48449
|
+
databaseId: { __rl: true, mode: "id", value: '={{ $json.databaseId || $json.database_id || "" }}' },
|
|
48405
48450
|
simple: true,
|
|
48406
48451
|
returnAll: false,
|
|
48407
|
-
limit:
|
|
48408
|
-
|
|
48452
|
+
limit: 3,
|
|
48453
|
+
options: {}
|
|
48409
48454
|
}
|
|
48410
48455
|
},
|
|
48411
48456
|
{
|
|
@@ -48413,21 +48458,41 @@ var SERVICE_MAPPINGS = [
|
|
|
48413
48458
|
nodeType: "n8n-nodes-base.googleSheets",
|
|
48414
48459
|
displayName: "Google Sheets",
|
|
48415
48460
|
role: "action",
|
|
48416
|
-
|
|
48461
|
+
defaultOperation: "append",
|
|
48462
|
+
defaultResource: "sheet",
|
|
48463
|
+
credentialType: "googleSheetsOAuth2Api",
|
|
48464
|
+
defaultParameters: {
|
|
48465
|
+
documentId: { __rl: true, mode: "url", value: '={{ $json.spreadsheetUrl || $json.spreadsheet_id || "" }}' },
|
|
48466
|
+
sheetName: { __rl: true, mode: "list", value: '={{ $json.sheetName || "Sheet1" }}' },
|
|
48467
|
+
columns: { mappingMode: "autoMapInputData", value: {} },
|
|
48468
|
+
options: {}
|
|
48469
|
+
}
|
|
48417
48470
|
},
|
|
48418
48471
|
{
|
|
48419
48472
|
keywords: ["airtable"],
|
|
48420
48473
|
nodeType: "n8n-nodes-base.airtable",
|
|
48421
48474
|
displayName: "Airtable",
|
|
48422
48475
|
role: "action",
|
|
48423
|
-
|
|
48476
|
+
defaultOperation: "create",
|
|
48477
|
+
credentialType: "airtableTokenApi",
|
|
48478
|
+
defaultParameters: {
|
|
48479
|
+
base: { __rl: true, mode: "id", value: '={{ $json.baseId || "" }}' },
|
|
48480
|
+
table: { __rl: true, mode: "id", value: '={{ $json.tableId || "" }}' },
|
|
48481
|
+
columns: { mappingMode: "autoMapInputData", value: {} },
|
|
48482
|
+
options: {}
|
|
48483
|
+
}
|
|
48424
48484
|
},
|
|
48425
48485
|
{
|
|
48426
48486
|
keywords: ["postgres", "postgresql", "database"],
|
|
48427
48487
|
nodeType: "n8n-nodes-base.postgres",
|
|
48428
48488
|
displayName: "Postgres",
|
|
48429
48489
|
role: "action",
|
|
48430
|
-
|
|
48490
|
+
defaultOperation: "executeQuery",
|
|
48491
|
+
credentialType: "postgres",
|
|
48492
|
+
defaultParameters: {
|
|
48493
|
+
query: "SELECT 1 AS ok",
|
|
48494
|
+
options: {}
|
|
48495
|
+
}
|
|
48431
48496
|
},
|
|
48432
48497
|
// ── Dev Tools ──
|
|
48433
48498
|
{
|
|
@@ -48435,7 +48500,16 @@ var SERVICE_MAPPINGS = [
|
|
|
48435
48500
|
nodeType: "n8n-nodes-base.github",
|
|
48436
48501
|
displayName: "GitHub",
|
|
48437
48502
|
role: "action",
|
|
48438
|
-
|
|
48503
|
+
defaultOperation: "create",
|
|
48504
|
+
defaultResource: "issue",
|
|
48505
|
+
credentialType: "githubApi",
|
|
48506
|
+
defaultParameters: {
|
|
48507
|
+
owner: '={{ $json.owner || "" }}',
|
|
48508
|
+
repository: '={{ $json.repo || $json.repository || "" }}',
|
|
48509
|
+
title: '={{ $json.title || $json.subject || "New issue" }}',
|
|
48510
|
+
body: '={{ $json.body || $json.text || $json.message || "" }}',
|
|
48511
|
+
additionalFields: {}
|
|
48512
|
+
}
|
|
48439
48513
|
},
|
|
48440
48514
|
// ── Web APIs → HTTP Request ──
|
|
48441
48515
|
{
|
|
@@ -48504,22 +48578,34 @@ var SERVICE_MAPPINGS = [
|
|
|
48504
48578
|
keywords: ["http request", "api call", "rest api", "fetch"],
|
|
48505
48579
|
nodeType: "n8n-nodes-base.httpRequest",
|
|
48506
48580
|
displayName: "HTTP Request",
|
|
48507
|
-
role: "action"
|
|
48581
|
+
role: "action",
|
|
48582
|
+
defaultParameters: {
|
|
48583
|
+
method: "GET",
|
|
48584
|
+
url: '={{ $json.url || "https://httpbin.org/get" }}'
|
|
48585
|
+
}
|
|
48508
48586
|
}
|
|
48509
48587
|
];
|
|
48510
48588
|
function detectServicesInOrder(description) {
|
|
48511
48589
|
const lower = description.toLowerCase();
|
|
48512
48590
|
const detected = [];
|
|
48513
48591
|
const usedNodeTypes = /* @__PURE__ */ new Set();
|
|
48592
|
+
const triggerServiceNames = /* @__PURE__ */ new Set();
|
|
48514
48593
|
for (const mapping of SERVICE_MAPPINGS) {
|
|
48515
48594
|
const dedupeKey = mapping.nodeType === "n8n-nodes-base.httpRequest" ? `${mapping.nodeType}:${mapping.keywords[0]}` : mapping.nodeType;
|
|
48516
48595
|
if (usedNodeTypes.has(dedupeKey))
|
|
48517
48596
|
continue;
|
|
48597
|
+
if (mapping.role === "action" && mapping.keywords.some((kw) => triggerServiceNames.has(kw))) {
|
|
48598
|
+
continue;
|
|
48599
|
+
}
|
|
48518
48600
|
for (const keyword of mapping.keywords) {
|
|
48519
48601
|
const idx = lower.indexOf(keyword);
|
|
48520
48602
|
if (idx !== -1) {
|
|
48521
48603
|
detected.push({ index: idx, mapping, matchedKeyword: keyword });
|
|
48522
48604
|
usedNodeTypes.add(dedupeKey);
|
|
48605
|
+
if (mapping.role === "trigger") {
|
|
48606
|
+
for (const kw of mapping.keywords)
|
|
48607
|
+
triggerServiceNames.add(kw.split(/\s/)[0]);
|
|
48608
|
+
}
|
|
48523
48609
|
break;
|
|
48524
48610
|
}
|
|
48525
48611
|
}
|
|
@@ -48610,9 +48696,7 @@ function applyExtractedParams(spec, params, description) {
|
|
|
48610
48696
|
if (nodeTypeLower.includes("telegram") && params.telegramChatId) {
|
|
48611
48697
|
spec.parameters = {
|
|
48612
48698
|
...spec.parameters,
|
|
48613
|
-
chatId: params.telegramChatId
|
|
48614
|
-
text: "={{ $json.text || $json.output || JSON.stringify($json).substring(0, 500) }}",
|
|
48615
|
-
additionalFields: {}
|
|
48699
|
+
chatId: params.telegramChatId
|
|
48616
48700
|
};
|
|
48617
48701
|
}
|
|
48618
48702
|
if (nodeTypeLower.includes("chainllm")) {
|
|
@@ -48651,13 +48735,35 @@ function buildChainLlmPrompt(description) {
|
|
|
48651
48735
|
{{ ($json.extract || $json.description || $json.text || JSON.stringify($json)).substring(0, 800) }}`;
|
|
48652
48736
|
}
|
|
48653
48737
|
function generateTestPayload(description, params) {
|
|
48738
|
+
const lower = description.toLowerCase();
|
|
48654
48739
|
const payload = {};
|
|
48655
|
-
if (
|
|
48740
|
+
if (lower.includes("company")) {
|
|
48656
48741
|
payload.company = "Tesla";
|
|
48657
48742
|
}
|
|
48658
|
-
if (
|
|
48743
|
+
if (lower.includes("meeting") || lower.includes("topic")) {
|
|
48659
48744
|
payload.meeting_topic = "Q1 Partnership Review";
|
|
48660
48745
|
}
|
|
48746
|
+
if (lower.includes("telegram")) {
|
|
48747
|
+
payload.chatId = process.env.P58_TELEGRAM_CHAT_ID ?? "";
|
|
48748
|
+
payload.text = payload.text ?? "Test message from build_workflow";
|
|
48749
|
+
}
|
|
48750
|
+
if (lower.includes("slack")) {
|
|
48751
|
+
payload.text = payload.text ?? "Test message from build_workflow";
|
|
48752
|
+
}
|
|
48753
|
+
if (lower.includes("notion")) {
|
|
48754
|
+
payload.text = payload.text ?? "Test entry";
|
|
48755
|
+
payload.title = "Test entry from build_workflow";
|
|
48756
|
+
}
|
|
48757
|
+
if (lower.includes("postgres") || lower.includes("database")) {
|
|
48758
|
+
payload.query = "SELECT 1 AS ok";
|
|
48759
|
+
}
|
|
48760
|
+
if (lower.includes("github")) {
|
|
48761
|
+
payload.title = "Test issue from build_workflow";
|
|
48762
|
+
payload.body = "Automated test \u2014 can be deleted";
|
|
48763
|
+
}
|
|
48764
|
+
if (lower.includes("sheets") || lower.includes("spreadsheet")) {
|
|
48765
|
+
payload.data = { name: "test", value: 1 };
|
|
48766
|
+
}
|
|
48661
48767
|
if (Object.keys(payload).length === 0) {
|
|
48662
48768
|
payload.input = "test data";
|
|
48663
48769
|
payload.test = true;
|
|
@@ -49040,8 +49146,8 @@ async function pollCloneExecution(config2, cloneId, budgetMs) {
|
|
|
49040
49146
|
const latest = list.executions[0];
|
|
49041
49147
|
if (latest?.id) {
|
|
49042
49148
|
const full = await getExecution(config2, latest.id, true);
|
|
49043
|
-
if (full.finished) {
|
|
49044
|
-
const hasError = full.status === "error" || full.error != null;
|
|
49149
|
+
if (full.finished || full.status === "error" || full.status === "crashed") {
|
|
49150
|
+
const hasError = full.status === "error" || full.status === "crashed" || full.error != null;
|
|
49045
49151
|
return { execId: latest.id, execStatus: hasError ? "error" : "success", nodeDebug: extractNodeDebugData(full) };
|
|
49046
49152
|
}
|
|
49047
49153
|
}
|
|
@@ -49074,6 +49180,15 @@ async function executeCloneTest(workflowId, testPayload, timeoutMs) {
|
|
|
49074
49180
|
const config2 = buildCloneApiConfig(timeoutMs);
|
|
49075
49181
|
const workflow = await getWorkflow(config2, workflowId);
|
|
49076
49182
|
const nodes = workflow.nodes ?? [];
|
|
49183
|
+
const hasR2W = await hasRespondToWebhookNode(workflow);
|
|
49184
|
+
if (hasR2W) {
|
|
49185
|
+
return {
|
|
49186
|
+
success: false,
|
|
49187
|
+
error: "Cannot test via clone: workflow contains a Respond to Webhook node. Use direct webhook POST (test_workflow) instead.",
|
|
49188
|
+
duration_ms: Math.round(performance.now() - start),
|
|
49189
|
+
method: "clone_and_execute"
|
|
49190
|
+
};
|
|
49191
|
+
}
|
|
49077
49192
|
const connections = workflow.connections ?? {};
|
|
49078
49193
|
const { cloneNodes, cloneConnections, webhookPath } = buildCloneSpec(nodes, connections, workflow.settings);
|
|
49079
49194
|
const { calculateAdaptiveTimeout: calculateAdaptiveTimeout2 } = await Promise.resolve().then(() => (init_timeout(), timeout_exports));
|
|
@@ -49105,6 +49220,28 @@ async function executeCloneTest(workflowId, testPayload, timeoutMs) {
|
|
|
49105
49220
|
}
|
|
49106
49221
|
}
|
|
49107
49222
|
}
|
|
49223
|
+
async function retryWebhookTest(path3, testPayload, timeoutMs, start) {
|
|
49224
|
+
const delays = [1e3, 2e3, 4e3];
|
|
49225
|
+
let lastErr = "";
|
|
49226
|
+
for (const delayMs of delays) {
|
|
49227
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
49228
|
+
try {
|
|
49229
|
+
const out = await withTimeout(postWebhook(buildN8nHostUrl(), path3, testPayload ?? {}, timeoutMs), timeoutMs, "build_workflow:retry");
|
|
49230
|
+
return { success: true, output: out, duration_ms: Math.round(performance.now() - start), method: "webhook_inline" };
|
|
49231
|
+
} catch (err) {
|
|
49232
|
+
lastErr = err instanceof Error ? err.message : String(err);
|
|
49233
|
+
if (!lastErr.includes("404")) {
|
|
49234
|
+
return { success: false, error: lastErr, duration_ms: Math.round(performance.now() - start), method: "webhook_inline" };
|
|
49235
|
+
}
|
|
49236
|
+
}
|
|
49237
|
+
}
|
|
49238
|
+
return {
|
|
49239
|
+
success: false,
|
|
49240
|
+
error: "Webhook endpoint not ready after 3 retries. The workflow was deployed and activated successfully \u2014 test it manually with test_workflow.",
|
|
49241
|
+
duration_ms: Math.round(performance.now() - start),
|
|
49242
|
+
method: "webhook_inline"
|
|
49243
|
+
};
|
|
49244
|
+
}
|
|
49108
49245
|
async function runTestStep(workflow, workflowId, testPayload, timeoutMs) {
|
|
49109
49246
|
const start = performance.now();
|
|
49110
49247
|
const triggerType = await detectTriggerType(workflow);
|
|
@@ -49114,7 +49251,12 @@ async function runTestStep(workflow, workflowId, testPayload, timeoutMs) {
|
|
|
49114
49251
|
return { success: false, error: "No webhook path configured", duration_ms: 0, method: "webhook_inline" };
|
|
49115
49252
|
const testResult = await executeWebhookTest(path3, testPayload, timeoutMs, start);
|
|
49116
49253
|
if (!testResult.success && testResult.error?.includes("404")) {
|
|
49117
|
-
|
|
49254
|
+
const hasR2W = await hasRespondToWebhookNode(workflow);
|
|
49255
|
+
if (hasR2W) {
|
|
49256
|
+
import_logging62.logger.info("build_workflow: Respond to Webhook detected, retrying direct POST (no clone)", { workflowId });
|
|
49257
|
+
return retryWebhookTest(path3, testPayload, timeoutMs, start);
|
|
49258
|
+
}
|
|
49259
|
+
import_logging62.logger.info("build_workflow: webhook 404, falling back to clone-and-execute", { workflowId });
|
|
49118
49260
|
return executeCloneTest(workflowId, testPayload, timeoutMs);
|
|
49119
49261
|
}
|
|
49120
49262
|
return testResult;
|
|
@@ -49148,6 +49290,7 @@ async function runMainPipeline(assembled, args, timeoutMs, correlationId) {
|
|
|
49148
49290
|
return runValidatedDeployPipeline(assembled, "auto", deployFn, timeoutMs, "build_workflow", correlationId);
|
|
49149
49291
|
}
|
|
49150
49292
|
function buildSuccessPayload(args, result, builtSubWorkflows, workflowId, testResult, startTime) {
|
|
49293
|
+
const testFailed = testResult !== void 0 && !testResult.success;
|
|
49151
49294
|
return {
|
|
49152
49295
|
success: true,
|
|
49153
49296
|
workflow_id: workflowId,
|
|
@@ -49157,7 +49300,9 @@ function buildSuccessPayload(args, result, builtSubWorkflows, workflowId, testRe
|
|
|
49157
49300
|
validation: buildValidationResult(result, result.fixesApplied.length),
|
|
49158
49301
|
execution: testResult ? { tested: true, success: testResult.success, output: testResult.output, error: testResult.error, duration_ms: testResult.duration_ms, execution_id: testResult.execution_id, node_debug: testResult.node_debug, method: testResult.method } : { tested: false, reason: "test: false was explicitly set" },
|
|
49159
49302
|
build_time_ms: Math.round(performance.now() - startTime),
|
|
49160
|
-
tokens_saved_estimate: Math.max(args.nodes.length * 2e3, 4e3)
|
|
49303
|
+
tokens_saved_estimate: Math.max(args.nodes.length * 2e3, 4e3),
|
|
49304
|
+
...testResult !== void 0 ? { test_passed: testResult.success } : {},
|
|
49305
|
+
...testFailed ? { test_error: testResult.error ?? "Test failed" } : {}
|
|
49161
49306
|
};
|
|
49162
49307
|
}
|
|
49163
49308
|
async function buildSuccessResponse2(args, result, builtSubWorkflows, timeoutMs, startTime) {
|
|
@@ -49545,8 +49690,9 @@ function extractWebhookPathFromSpec(cleanedArgs) {
|
|
|
49545
49690
|
function buildRichResponseFields(result, cleanedArgs, exec) {
|
|
49546
49691
|
const nodes = cleanedArgs.nodes ?? [];
|
|
49547
49692
|
const nodeFlow = nodes.map((n) => n.name || String(n.type ?? "").split(".").pop()).join(" \u2192 ");
|
|
49693
|
+
const testFailed = exec?.tested && !exec.success;
|
|
49548
49694
|
const parts = [
|
|
49549
|
-
`\u2705 Workflow "${result.workflow_name}" deployed with ${nodes.length} nodes.`
|
|
49695
|
+
testFailed ? `\u26A0\uFE0F WORKFLOW DEPLOYED BUT TEST FAILED: "${result.workflow_name}" (${nodes.length} nodes) \u2014 ${exec?.error ?? "unknown error"}` : `\u2705 Workflow "${result.workflow_name}" deployed with ${nodes.length} nodes.`
|
|
49550
49696
|
];
|
|
49551
49697
|
if (nodeFlow)
|
|
49552
49698
|
parts.push(`Flow: ${nodeFlow}`);
|
|
@@ -51035,10 +51181,10 @@ async function getCatalogHealth() {
|
|
|
51035
51181
|
return CATALOG_HEALTH_FALLBACK;
|
|
51036
51182
|
}
|
|
51037
51183
|
}
|
|
51038
|
-
function collectIssues(apiKeySet,
|
|
51184
|
+
function collectIssues(apiKeySet, workflowEngineConnected, probes, enhancedIntelligenceAvailable, invalidCredentials, cbState) {
|
|
51039
51185
|
const issues = [];
|
|
51040
51186
|
if (cbState && cbState !== "closed") {
|
|
51041
|
-
issues.push("\u26D4
|
|
51187
|
+
issues.push("\u26D4 INTELLIGENCE TEMPORARILY UNAVAILABLE \u2014 enhanced catalog features are resetting. DO NOT call build_workflow or use Bash to work around it. Call setup_check again in 60 seconds. If still unavailable after 30 minutes, report to the user and stop.");
|
|
51042
51188
|
}
|
|
51043
51189
|
if (!apiKeySet) {
|
|
51044
51190
|
issues.push("N8N_API_KEY not set \u2014 Tier 2-7 deploy tools unavailable");
|
|
@@ -51048,26 +51194,52 @@ function collectIssues(apiKeySet, n8nConnected, probes, dbConnected, dbError, cb
|
|
|
51048
51194
|
const reachable = probes.filter((p) => p.reachable);
|
|
51049
51195
|
if (reachable.length > 0) {
|
|
51050
51196
|
const probeUrl = reachable[0].url.replace("/api/v1/workflows", "");
|
|
51051
|
-
issues.push(`N8N_API_URL not set \u2014
|
|
51197
|
+
issues.push(`N8N_API_URL not set \u2014 workflow engine detected at ${probeUrl}. Set N8N_API_URL=${probeUrl}/api/v1 in your MCP config.`);
|
|
51052
51198
|
} else {
|
|
51053
|
-
issues.push("N8N_API_URL not set \u2014 no
|
|
51199
|
+
issues.push("N8N_API_URL not set \u2014 no workflow engine detected on localhost:5678 or localhost:5679");
|
|
51054
51200
|
}
|
|
51055
51201
|
}
|
|
51056
|
-
if (apiKeySet && !
|
|
51057
|
-
issues.push("N8N_API_KEY is set but
|
|
51202
|
+
if (apiKeySet && !workflowEngineConnected) {
|
|
51203
|
+
issues.push("N8N_API_KEY is set but workflow engine is unreachable \u2014 check N8N_API_URL and ensure n8n is running");
|
|
51204
|
+
}
|
|
51205
|
+
if (!enhancedIntelligenceAvailable) {
|
|
51206
|
+
issues.push("Enhanced intelligence unavailable \u2014 using built-in catalog. All tools fully functional.");
|
|
51058
51207
|
}
|
|
51059
|
-
if (
|
|
51060
|
-
|
|
51061
|
-
issues.push(`Database unavailable${detail} \u2014 catalog features degraded, pattern fallback active`);
|
|
51208
|
+
if (invalidCredentials > 0) {
|
|
51209
|
+
issues.push(`\u26A0\uFE0F ${invalidCredentials} credential(s) have connectivity issues \u2014 run list_credentials for details`);
|
|
51062
51210
|
}
|
|
51063
51211
|
return issues;
|
|
51064
51212
|
}
|
|
51213
|
+
async function probeWorkflowEngine(n8nUrl) {
|
|
51214
|
+
const probe = await probeN8nUrl(`${n8nUrl}/settings`);
|
|
51215
|
+
return { connected: probe.reachable, error: probe.error };
|
|
51216
|
+
}
|
|
51217
|
+
function buildCredentialHealth(cacheStatus, credentials) {
|
|
51218
|
+
if (!cacheStatus.loaded)
|
|
51219
|
+
return null;
|
|
51220
|
+
const types = [...new Set(credentials.map((c) => c.type))];
|
|
51221
|
+
const h = cacheStatus.health_summary;
|
|
51222
|
+
return {
|
|
51223
|
+
total: cacheStatus.count,
|
|
51224
|
+
valid: h?.valid ?? 0,
|
|
51225
|
+
invalid: h?.invalid ?? 0,
|
|
51226
|
+
untested: h?.untested ?? cacheStatus.count,
|
|
51227
|
+
types
|
|
51228
|
+
};
|
|
51229
|
+
}
|
|
51065
51230
|
async function buildReport() {
|
|
51066
51231
|
const apiKeySet = Boolean(process.env.N8N_API_KEY);
|
|
51067
51232
|
const n8nUrl = process.env.N8N_API_URL ?? process.env.N8N_API_BASE_URL ?? null;
|
|
51233
|
+
let workflowEngineConnected = false;
|
|
51234
|
+
if (n8nUrl) {
|
|
51235
|
+
const engineProbe = await probeWorkflowEngine(n8nUrl);
|
|
51236
|
+
workflowEngineConnected = engineProbe.connected;
|
|
51237
|
+
}
|
|
51068
51238
|
const cacheStatus = getCredentialCacheStatus();
|
|
51069
|
-
const n8nConnected = cacheStatus.loaded;
|
|
51070
51239
|
const credentialCount = cacheStatus.loaded ? cacheStatus.count : null;
|
|
51240
|
+
const credentials = cacheStatus.loaded ? await getPreloadedCredentials() : [];
|
|
51241
|
+
const credentialHealth = buildCredentialHealth(cacheStatus, credentials);
|
|
51242
|
+
const invalidCredentials = credentialHealth?.invalid ?? 0;
|
|
51071
51243
|
let probes;
|
|
51072
51244
|
if (!n8nUrl) {
|
|
51073
51245
|
probes = await discoverN8nInstances();
|
|
@@ -51076,7 +51248,9 @@ async function buildReport() {
|
|
|
51076
51248
|
const catalogHealth = await getCatalogHealth();
|
|
51077
51249
|
const cbStatus = import_validatorPostgresClient16.circuitBreaker.getStatus();
|
|
51078
51250
|
const accessState = await getRuntimeAccessState();
|
|
51079
|
-
const
|
|
51251
|
+
const enhancedIntelligenceAvailable = dbHealth.connected;
|
|
51252
|
+
const intelligenceStatus = dbHealth.connected ? void 0 : "Running with built-in catalog (offline mode)";
|
|
51253
|
+
const issues = collectIssues(apiKeySet, workflowEngineConnected, probes, enhancedIntelligenceAvailable, invalidCredentials, cbStatus.state);
|
|
51080
51254
|
const toolCounts = buildToolCounts();
|
|
51081
51255
|
const report = {
|
|
51082
51256
|
server_version: config.SERVER_VERSION,
|
|
@@ -51086,12 +51260,12 @@ async function buildReport() {
|
|
|
51086
51260
|
allowlist_status: accessState.allowlist_status,
|
|
51087
51261
|
n8n_configured: apiKeySet,
|
|
51088
51262
|
n8n_url: n8nUrl,
|
|
51089
|
-
|
|
51263
|
+
workflow_engine_connected: workflowEngineConnected,
|
|
51090
51264
|
n8n_api_key_set: apiKeySet,
|
|
51091
51265
|
credential_count: credentialCount,
|
|
51092
|
-
|
|
51093
|
-
|
|
51094
|
-
...
|
|
51266
|
+
credential_health: credentialHealth,
|
|
51267
|
+
enhanced_intelligence_available: enhancedIntelligenceAvailable,
|
|
51268
|
+
...intelligenceStatus ? { intelligence_status: intelligenceStatus } : {},
|
|
51095
51269
|
catalog: catalogHealth,
|
|
51096
51270
|
db_circuit_breaker: {
|
|
51097
51271
|
state: cbStatus.state,
|
|
@@ -51130,9 +51304,10 @@ var setupCheckToolDefinition = {
|
|
|
51130
51304
|
|
|
51131
51305
|
Returns a diagnostic report including:
|
|
51132
51306
|
- Server version
|
|
51133
|
-
- n8n
|
|
51307
|
+
- workflow_engine_connected: whether the n8n API is actually reachable (probe-based)
|
|
51134
51308
|
- n8n URL (from env var or auto-detected)
|
|
51135
|
-
-
|
|
51309
|
+
- credential_count + credential_health: credentials loaded and their validity stats
|
|
51310
|
+
- enhanced_intelligence_available: whether Path58 premium catalog data is available
|
|
51136
51311
|
- Tool availability by tier
|
|
51137
51312
|
- List of issues with actionable guidance
|
|
51138
51313
|
- Link to the setup guide
|