n8n-workflow-builder-mcp 0.1.0

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.
Files changed (595) hide show
  1. package/.cursor/rules/cursor_rules.mdc +53 -0
  2. package/.cursor/rules/dev_workflow.mdc +219 -0
  3. package/.cursor/rules/mcp.mdc +430 -0
  4. package/.cursor/rules/self_improve.mdc +72 -0
  5. package/.cursor/rules/taskmaster.mdc +382 -0
  6. package/.cursorignore +1 -0
  7. package/.cursorrules +4 -0
  8. package/.env.example +23 -0
  9. package/.eslintrc.json +38 -0
  10. package/.github/workflows/npm-publish-github-packages.yml +55 -0
  11. package/.prettierrc +9 -0
  12. package/.roo/rules/dev_workflow.md +219 -0
  13. package/.roo/rules/mcp.md +430 -0
  14. package/.roo/rules/roo_rules.md +53 -0
  15. package/.roo/rules/self_improve.md +72 -0
  16. package/.roo/rules/taskmaster.md +382 -0
  17. package/.roo/rules-architect/architect-rules +93 -0
  18. package/.roo/rules-ask/ask-rules +89 -0
  19. package/.roo/rules-boomerang/boomerang-rules +181 -0
  20. package/.roo/rules-code/code-rules +61 -0
  21. package/.roo/rules-debug/debug-rules +68 -0
  22. package/.roo/rules-test/test-rules +61 -0
  23. package/.roomodes +63 -0
  24. package/.taskmasterconfig +31 -0
  25. package/.windsurfrules +2382 -0
  26. package/LICENSE +21 -0
  27. package/README.md +210 -0
  28. package/config/credentials/credentials.json +1 -0
  29. package/config/default.js +41 -0
  30. package/package.json +56 -0
  31. package/scripts/demo-n8n-integration.js +161 -0
  32. package/scripts/demo-workflow-generator.js +102 -0
  33. package/scripts/init.sh +36 -0
  34. package/scripts/prd.txt +197 -0
  35. package/src/index.ts +1440 -0
  36. package/src/middleware/auth.js +273 -0
  37. package/src/middleware/authorize.js +183 -0
  38. package/src/middleware/logging.js +64 -0
  39. package/src/middleware/mcp.js +187 -0
  40. package/src/middleware/rateLimiter.js +82 -0
  41. package/src/middleware/validation.js +241 -0
  42. package/src/models/credential.js +359 -0
  43. package/src/models/llmService.js +236 -0
  44. package/src/models/n8nIntegration.js +542 -0
  45. package/src/models/storage.js +196 -0
  46. package/src/models/tool.js +148 -0
  47. package/src/models/user.js +164 -0
  48. package/src/models/workflow.js +229 -0
  49. package/src/routes/toolDefinitions.js +62 -0
  50. package/src/routes/toolExecution.js +79 -0
  51. package/src/tools/__index.js +242 -0
  52. package/src/tools/connectionManagement.js +500 -0
  53. package/src/tools/n8nIntegration.js +370 -0
  54. package/src/tools/nodeDiscovery.js +488 -0
  55. package/src/tools/nodeManagement.js +674 -0
  56. package/src/tools/toolDefinitions.js +660 -0
  57. package/src/tools/workflowCreation.js +100 -0
  58. package/src/tools/workflowGenerator.js +152 -0
  59. package/src/tools/workflowStorage.js +113 -0
  60. package/src/tools/workflowTesting.js +285 -0
  61. package/src/utils/encryption.js +164 -0
  62. package/src/utils/logger.js +84 -0
  63. package/src/utils/mcp.js +85 -0
  64. package/src/utils/securityLogger.js +109 -0
  65. package/tests/auth.test.js +402 -0
  66. package/tests/authorize.test.js +208 -0
  67. package/tests/run-memory-tests.js +55 -0
  68. package/tests/run-tests.js +55 -0
  69. package/tests/server.test.js +203 -0
  70. package/tests/unit/add-ai-connections.test.js +385 -0
  71. package/tests/unit/connectionManagement.test.js +309 -0
  72. package/tests/unit/langchain-llm-format.test.js +259 -0
  73. package/tests/unit/memory-connection.test.js +140 -0
  74. package/tests/unit/memory-integration.test.js +253 -0
  75. package/tests/unit/n8nIntegration.test.js +291 -0
  76. package/tests/unit/nodeDiscovery.test.js +270 -0
  77. package/tests/unit/nodeManagement.test.js +522 -0
  78. package/tests/unit/utils/mcp-test-utils.js +94 -0
  79. package/tests/unit/workflowCreation.test.js +110 -0
  80. package/tests/unit/workflowTesting.test.js +269 -0
  81. package/tests/user.test.js +181 -0
  82. package/tsconfig.json +20 -0
  83. package/workflow_nodes/Brandfetch.json +85 -0
  84. package/workflow_nodes/WorkflowTrigger.json +28 -0
  85. package/workflow_nodes/actionNetwork.json +218 -0
  86. package/workflow_nodes/activeCampaign.json +722 -0
  87. package/workflow_nodes/activeCampaignTrigger.json +52 -0
  88. package/workflow_nodes/acuitySchedulingTrigger.json +8 -0
  89. package/workflow_nodes/adalo.json +123 -0
  90. package/workflow_nodes/affinity.json +203 -0
  91. package/workflow_nodes/affinityTrigger.json +124 -0
  92. package/workflow_nodes/aggregate.json +119 -0
  93. package/workflow_nodes/agileCrm.json +503 -0
  94. package/workflow_nodes/aiTransform.json +17 -0
  95. package/workflow_nodes/airtable.json +226 -0
  96. package/workflow_nodes/airtableTrigger.json +120 -0
  97. package/workflow_nodes/airtop.json +10 -0
  98. package/workflow_nodes/amqp.json +62 -0
  99. package/workflow_nodes/amqpTrigger.json +8 -0
  100. package/workflow_nodes/apiTemplateIo.json +147 -0
  101. package/workflow_nodes/asana.json +446 -0
  102. package/workflow_nodes/asanaTrigger.json +52 -0
  103. package/workflow_nodes/automizy.json +195 -0
  104. package/workflow_nodes/autopilot.json +287 -0
  105. package/workflow_nodes/autopilotTrigger.json +8 -0
  106. package/workflow_nodes/awsCertificateManager.json +223 -0
  107. package/workflow_nodes/awsComprehend.json +125 -0
  108. package/workflow_nodes/awsDynamoDb.json +251 -0
  109. package/workflow_nodes/awsElb.json +174 -0
  110. package/workflow_nodes/awsLambda.json +69 -0
  111. package/workflow_nodes/awsRekognition.json +191 -0
  112. package/workflow_nodes/awsS3.json +32 -0
  113. package/workflow_nodes/awsSes.json +302 -0
  114. package/workflow_nodes/awsSns.json +110 -0
  115. package/workflow_nodes/awsSnsTrigger.json +47 -0
  116. package/workflow_nodes/awsSqs.json +140 -0
  117. package/workflow_nodes/awsTextract.json +43 -0
  118. package/workflow_nodes/awsTranscribe.json +217 -0
  119. package/workflow_nodes/azureCosmosDb.json +8 -0
  120. package/workflow_nodes/azureStorage.json +17 -0
  121. package/workflow_nodes/bambooHr.json +8 -0
  122. package/workflow_nodes/bannerbear.json +126 -0
  123. package/workflow_nodes/baserow.json +277 -0
  124. package/workflow_nodes/beeminder.json +146 -0
  125. package/workflow_nodes/bitbucketTrigger.json +62 -0
  126. package/workflow_nodes/bitly.json +130 -0
  127. package/workflow_nodes/bitwarden.json +224 -0
  128. package/workflow_nodes/box.json +457 -0
  129. package/workflow_nodes/boxTrigger.json +8 -0
  130. package/workflow_nodes/brevo.json +41 -0
  131. package/workflow_nodes/brevoTrigger.json +145 -0
  132. package/workflow_nodes/bubble.json +212 -0
  133. package/workflow_nodes/calTrigger.json +91 -0
  134. package/workflow_nodes/calendlyTrigger.json +71 -0
  135. package/workflow_nodes/chargebee.json +217 -0
  136. package/workflow_nodes/chargebeeTrigger.json +187 -0
  137. package/workflow_nodes/circleCi.json +89 -0
  138. package/workflow_nodes/ciscoWebex.json +593 -0
  139. package/workflow_nodes/ciscoWebexTrigger.json +159 -0
  140. package/workflow_nodes/clearbit.json +138 -0
  141. package/workflow_nodes/clickUp.json +793 -0
  142. package/workflow_nodes/clickUpTrigger.json +188 -0
  143. package/workflow_nodes/clockify.json +372 -0
  144. package/workflow_nodes/clockifyTrigger.json +26 -0
  145. package/workflow_nodes/cloudflare.json +103 -0
  146. package/workflow_nodes/cockpit.json +161 -0
  147. package/workflow_nodes/coda.json +242 -0
  148. package/workflow_nodes/code.json +40 -0
  149. package/workflow_nodes/coinGecko.json +363 -0
  150. package/workflow_nodes/compareDatasets.json +14 -0
  151. package/workflow_nodes/compression.json +66 -0
  152. package/workflow_nodes/contentful.json +29 -0
  153. package/workflow_nodes/convertKit.json +159 -0
  154. package/workflow_nodes/convertKitTrigger.json +109 -0
  155. package/workflow_nodes/convertToFile.json +64 -0
  156. package/workflow_nodes/copper.json +239 -0
  157. package/workflow_nodes/copperTrigger.json +8 -0
  158. package/workflow_nodes/cortex.json +348 -0
  159. package/workflow_nodes/crateDb.json +90 -0
  160. package/workflow_nodes/cron.json +23 -0
  161. package/workflow_nodes/crowdDev.json +8 -0
  162. package/workflow_nodes/crowdDevTrigger.json +8 -0
  163. package/workflow_nodes/crypto.json +147 -0
  164. package/workflow_nodes/customerIo.json +206 -0
  165. package/workflow_nodes/customerIoTrigger.json +185 -0
  166. package/workflow_nodes/dateTime.json +39 -0
  167. package/workflow_nodes/debughelper.json +162 -0
  168. package/workflow_nodes/deepL.json +103 -0
  169. package/workflow_nodes/demio.json +187 -0
  170. package/workflow_nodes/dhl.json +53 -0
  171. package/workflow_nodes/discord.json +81 -0
  172. package/workflow_nodes/discourse.json +319 -0
  173. package/workflow_nodes/disqus.json +254 -0
  174. package/workflow_nodes/drift.json +112 -0
  175. package/workflow_nodes/dropbox.json +258 -0
  176. package/workflow_nodes/dropcontact.json +154 -0
  177. package/workflow_nodes/e2eTest.json +70 -0
  178. package/workflow_nodes/editImage.json +132 -0
  179. package/workflow_nodes/egoi.json +220 -0
  180. package/workflow_nodes/elasticSecurity.json +401 -0
  181. package/workflow_nodes/elasticsearch.json +422 -0
  182. package/workflow_nodes/emailReadImap.json +88 -0
  183. package/workflow_nodes/emailSend.json +38 -0
  184. package/workflow_nodes/emelia.json +201 -0
  185. package/workflow_nodes/emeliaTrigger.json +57 -0
  186. package/workflow_nodes/erpNext.json +139 -0
  187. package/workflow_nodes/errorTrigger.json +15 -0
  188. package/workflow_nodes/evaluationMetrics.json +21 -0
  189. package/workflow_nodes/eventbriteTrigger.json +125 -0
  190. package/workflow_nodes/executeCommand.json +25 -0
  191. package/workflow_nodes/executeWorkflow.json +102 -0
  192. package/workflow_nodes/executeWorkflowTrigger.json +65 -0
  193. package/workflow_nodes/executionData.json +35 -0
  194. package/workflow_nodes/extractFromFile.json +71 -0
  195. package/workflow_nodes/facebookGraphApi.json +234 -0
  196. package/workflow_nodes/facebookLeadAdsTrigger.json +8 -0
  197. package/workflow_nodes/facebookTrigger.json +112 -0
  198. package/workflow_nodes/figmaTrigger.json +8 -0
  199. package/workflow_nodes/filemaker.json +268 -0
  200. package/workflow_nodes/filter.json +24 -0
  201. package/workflow_nodes/flow.json +323 -0
  202. package/workflow_nodes/flowTrigger.json +52 -0
  203. package/workflow_nodes/form.json +25 -0
  204. package/workflow_nodes/formIoTrigger.json +59 -0
  205. package/workflow_nodes/formTrigger.json +8 -0
  206. package/workflow_nodes/formstackTrigger.json +8 -0
  207. package/workflow_nodes/freshdesk.json +584 -0
  208. package/workflow_nodes/freshservice.json +899 -0
  209. package/workflow_nodes/freshworksCrm.json +772 -0
  210. package/workflow_nodes/ftp.json +127 -0
  211. package/workflow_nodes/function.json +22 -0
  212. package/workflow_nodes/functionItem.json +22 -0
  213. package/workflow_nodes/gSuiteAdmin.json +562 -0
  214. package/workflow_nodes/getResponse.json +310 -0
  215. package/workflow_nodes/getResponseTrigger.json +82 -0
  216. package/workflow_nodes/ghost.json +290 -0
  217. package/workflow_nodes/git.json +184 -0
  218. package/workflow_nodes/github.json +732 -0
  219. package/workflow_nodes/githubTrigger.json +317 -0
  220. package/workflow_nodes/gitlab.json +544 -0
  221. package/workflow_nodes/gitlabTrigger.json +61 -0
  222. package/workflow_nodes/gmail.json +62 -0
  223. package/workflow_nodes/gmailTrigger.json +127 -0
  224. package/workflow_nodes/goToWebinar.json +430 -0
  225. package/workflow_nodes/gong.json +22 -0
  226. package/workflow_nodes/googleAds.json +116 -0
  227. package/workflow_nodes/googleAnalytics.json +28 -0
  228. package/workflow_nodes/googleBigQuery.json +38 -0
  229. package/workflow_nodes/googleBooks.json +154 -0
  230. package/workflow_nodes/googleBusinessProfile.json +277 -0
  231. package/workflow_nodes/googleBusinessProfileTrigger.json +55 -0
  232. package/workflow_nodes/googleCalendar.json +474 -0
  233. package/workflow_nodes/googleCalendarTrigger.json +72 -0
  234. package/workflow_nodes/googleChat.json +187 -0
  235. package/workflow_nodes/googleCloudNaturalLanguage.json +171 -0
  236. package/workflow_nodes/googleCloudStorage.json +466 -0
  237. package/workflow_nodes/googleContacts.json +481 -0
  238. package/workflow_nodes/googleDocs.json +312 -0
  239. package/workflow_nodes/googleDrive.json +920 -0
  240. package/workflow_nodes/googleDriveTrigger.json +181 -0
  241. package/workflow_nodes/googleFirebaseCloudFirestore.json +156 -0
  242. package/workflow_nodes/googleFirebaseRealtimeDatabase.json +75 -0
  243. package/workflow_nodes/googlePerspective.json +94 -0
  244. package/workflow_nodes/googleSheets.json +98 -0
  245. package/workflow_nodes/googleSheetsTrigger.json +192 -0
  246. package/workflow_nodes/googleSlides.json +186 -0
  247. package/workflow_nodes/googleTasks.json +198 -0
  248. package/workflow_nodes/googleTranslate.json +80 -0
  249. package/workflow_nodes/gotify.json +110 -0
  250. package/workflow_nodes/grafana.json +155 -0
  251. package/workflow_nodes/graphql.json +165 -0
  252. package/workflow_nodes/grist.json +13 -0
  253. package/workflow_nodes/gumroadTrigger.json +8 -0
  254. package/workflow_nodes/hackerNews.json +100 -0
  255. package/workflow_nodes/haloPSA.json +286 -0
  256. package/workflow_nodes/harvest.json +699 -0
  257. package/workflow_nodes/helpScout.json +629 -0
  258. package/workflow_nodes/helpScoutTrigger.json +8 -0
  259. package/workflow_nodes/highLevel.json +8 -0
  260. package/workflow_nodes/homeAssistant.json +201 -0
  261. package/workflow_nodes/html.json +118 -0
  262. package/workflow_nodes/htmlExtract.json +87 -0
  263. package/workflow_nodes/httpRequest.json +472 -0
  264. package/workflow_nodes/hubspot.json +62 -0
  265. package/workflow_nodes/hubspotTrigger.json +138 -0
  266. package/workflow_nodes/humanticAi.json +82 -0
  267. package/workflow_nodes/hunter.json +168 -0
  268. package/workflow_nodes/iCal.json +20 -0
  269. package/workflow_nodes/if.json +24 -0
  270. package/workflow_nodes/intercom.json +335 -0
  271. package/workflow_nodes/interval.json +8 -0
  272. package/workflow_nodes/invoiceNinja.json +882 -0
  273. package/workflow_nodes/invoiceNinjaTrigger.json +11 -0
  274. package/workflow_nodes/itemLists.json +313 -0
  275. package/workflow_nodes/iterable.json +168 -0
  276. package/workflow_nodes/jenkins.json +172 -0
  277. package/workflow_nodes/jira.json +529 -0
  278. package/workflow_nodes/jiraTrigger.json +308 -0
  279. package/workflow_nodes/jotFormTrigger.json +44 -0
  280. package/workflow_nodes/jwt.json +195 -0
  281. package/workflow_nodes/kafka.json +132 -0
  282. package/workflow_nodes/kafkaTrigger.json +11 -0
  283. package/workflow_nodes/keap.json +915 -0
  284. package/workflow_nodes/keapTrigger.json +37 -0
  285. package/workflow_nodes/kitemaker.json +153 -0
  286. package/workflow_nodes/koBoToolbox.json +337 -0
  287. package/workflow_nodes/koBoToolboxTrigger.json +8 -0
  288. package/workflow_nodes/langchain_Summarization Chain.json +60 -0
  289. package/workflow_nodes/langchain_agent.json +145 -0
  290. package/workflow_nodes/langchain_allowFileUploads.json +180 -0
  291. package/workflow_nodes/langchain_chainLlm.json +16 -0
  292. package/workflow_nodes/langchain_chainSummarization.json +119 -0
  293. package/workflow_nodes/langchain_code.json +62 -0
  294. package/workflow_nodes/langchain_documentBinaryInputLoader.json +8 -0
  295. package/workflow_nodes/langchain_documentDefaultDataLoader.json +8 -0
  296. package/workflow_nodes/langchain_documentGithubLoader.json +8 -0
  297. package/workflow_nodes/langchain_documentJsonInputLoader.json +8 -0
  298. package/workflow_nodes/langchain_embeddingDimensions.json +17 -0
  299. package/workflow_nodes/langchain_embeddingsAwsBedrock.json +8 -0
  300. package/workflow_nodes/langchain_embeddingsAzureOpenAi.json +151 -0
  301. package/workflow_nodes/langchain_embeddingsCohere.json +8 -0
  302. package/workflow_nodes/langchain_embeddingsGoogleGemini.json +8 -0
  303. package/workflow_nodes/langchain_embeddingsGoogleVertex.json +8 -0
  304. package/workflow_nodes/langchain_embeddingsHuggingFaceInference.json +8 -0
  305. package/workflow_nodes/langchain_embeddingsMistralCloud.json +8 -0
  306. package/workflow_nodes/langchain_embeddingsOllama.json +8 -0
  307. package/workflow_nodes/langchain_informationExtractor.json +81 -0
  308. package/workflow_nodes/langchain_lmChatAwsBedrock.json +8 -0
  309. package/workflow_nodes/langchain_lmChatAzureOpenAi.json +151 -0
  310. package/workflow_nodes/langchain_lmChatDeepSeek.json +10 -0
  311. package/workflow_nodes/langchain_lmChatGoogleGemini.json +31 -0
  312. package/workflow_nodes/langchain_lmChatGoogleVertex.json +32 -0
  313. package/workflow_nodes/langchain_lmChatGroq.json +8 -0
  314. package/workflow_nodes/langchain_lmChatMistralCloud.json +8 -0
  315. package/workflow_nodes/langchain_lmChatOllama.json +8 -0
  316. package/workflow_nodes/langchain_lmChatOpenAi.json +155 -0
  317. package/workflow_nodes/langchain_lmChatOpenRouter.json +10 -0
  318. package/workflow_nodes/langchain_lmChatXAiGrok.json +10 -0
  319. package/workflow_nodes/langchain_lmCohere.json +8 -0
  320. package/workflow_nodes/langchain_lmOllama.json +8 -0
  321. package/workflow_nodes/langchain_lmOpenAi.json +251 -0
  322. package/workflow_nodes/langchain_lmOpenHuggingFaceInference.json +8 -0
  323. package/workflow_nodes/langchain_manualChatTrigger.json +11 -0
  324. package/workflow_nodes/langchain_mcpClientTool.json +86 -0
  325. package/workflow_nodes/langchain_mcpTrigger.json +8 -0
  326. package/workflow_nodes/langchain_memoryBufferWindow.json +13 -0
  327. package/workflow_nodes/langchain_memoryChatRetriever.json +22 -0
  328. package/workflow_nodes/langchain_memoryManager.json +106 -0
  329. package/workflow_nodes/langchain_memoryMongoDbChat.json +10 -0
  330. package/workflow_nodes/langchain_memoryMotorhead.json +13 -0
  331. package/workflow_nodes/langchain_memoryPostgresChat.json +13 -0
  332. package/workflow_nodes/langchain_memoryRedisChat.json +15 -0
  333. package/workflow_nodes/langchain_memoryXata.json +14 -0
  334. package/workflow_nodes/langchain_memoryZep.json +13 -0
  335. package/workflow_nodes/langchain_model.json +155 -0
  336. package/workflow_nodes/langchain_mongoCollection.json +16 -0
  337. package/workflow_nodes/langchain_notice.json +22 -0
  338. package/workflow_nodes/langchain_openAiAssistant.json +132 -0
  339. package/workflow_nodes/langchain_options.json +17 -0
  340. package/workflow_nodes/langchain_outputParserAutofixing.json +8 -0
  341. package/workflow_nodes/langchain_outputParserItemList.json +8 -0
  342. package/workflow_nodes/langchain_outputParserStructured.json +12 -0
  343. package/workflow_nodes/langchain_pineconeNamespace.json +16 -0
  344. package/workflow_nodes/langchain_queryName.json +16 -0
  345. package/workflow_nodes/langchain_retrieverContextualCompression.json +8 -0
  346. package/workflow_nodes/langchain_retrieverMultiQuery.json +8 -0
  347. package/workflow_nodes/langchain_retrieverVectorStore.json +8 -0
  348. package/workflow_nodes/langchain_retrieverWorkflow.json +103 -0
  349. package/workflow_nodes/langchain_sentimentAnalysis.json +52 -0
  350. package/workflow_nodes/langchain_systemPromptTemplate.json +47 -0
  351. package/workflow_nodes/langchain_tableName.json +23 -0
  352. package/workflow_nodes/langchain_textClassifier.json +66 -0
  353. package/workflow_nodes/langchain_textSplitterCharacterTextSplitter.json +8 -0
  354. package/workflow_nodes/langchain_textSplitterRecursiveCharacterTextSplitter.json +8 -0
  355. package/workflow_nodes/langchain_textSplitterTokenSplitter.json +8 -0
  356. package/workflow_nodes/langchain_toolCalculator.json +8 -0
  357. package/workflow_nodes/langchain_toolCode.json +12 -0
  358. package/workflow_nodes/langchain_toolHttpRequest.json +232 -0
  359. package/workflow_nodes/langchain_toolSearXng.json +8 -0
  360. package/workflow_nodes/langchain_toolSerpApi.json +8 -0
  361. package/workflow_nodes/langchain_toolThink.json +8 -0
  362. package/workflow_nodes/langchain_toolVectorStore.json +11 -0
  363. package/workflow_nodes/langchain_toolWikipedia.json +8 -0
  364. package/workflow_nodes/langchain_toolWolframAlpha.json +8 -0
  365. package/workflow_nodes/langchain_toolWorkflow.json +8 -0
  366. package/workflow_nodes/langchain_vectorStoreInMemoryInsert.json +29 -0
  367. package/workflow_nodes/langchain_vectorStoreInMemoryLoad.json +8 -0
  368. package/workflow_nodes/langchain_vectorStorePineconeInsert.json +37 -0
  369. package/workflow_nodes/langchain_vectorStorePineconeLoad.json +8 -0
  370. package/workflow_nodes/langchain_vectorStoreSupabaseInsert.json +32 -0
  371. package/workflow_nodes/langchain_vectorStoreSupabaseLoad.json +8 -0
  372. package/workflow_nodes/langchain_vectorStoreZepInsert.json +46 -0
  373. package/workflow_nodes/langchain_vectorStoreZepLoad.json +8 -0
  374. package/workflow_nodes/ldap.json +182 -0
  375. package/workflow_nodes/lemlist.json +44 -0
  376. package/workflow_nodes/lemlistTrigger.json +45 -0
  377. package/workflow_nodes/limit.json +26 -0
  378. package/workflow_nodes/line.json +95 -0
  379. package/workflow_nodes/linear.json +151 -0
  380. package/workflow_nodes/linearTrigger.json +71 -0
  381. package/workflow_nodes/lingvaNex.json +66 -0
  382. package/workflow_nodes/linkedIn.json +142 -0
  383. package/workflow_nodes/localFileTrigger.json +120 -0
  384. package/workflow_nodes/lonescale.json +171 -0
  385. package/workflow_nodes/lonescaleTrigger.json +8 -0
  386. package/workflow_nodes/magento2.json +164 -0
  387. package/workflow_nodes/mailcheck.json +46 -0
  388. package/workflow_nodes/mailchimp.json +507 -0
  389. package/workflow_nodes/mailchimpTrigger.json +100 -0
  390. package/workflow_nodes/mailerLite.json +24 -0
  391. package/workflow_nodes/mailerLiteTrigger.json +74 -0
  392. package/workflow_nodes/mailgun.json +81 -0
  393. package/workflow_nodes/mailjet.json +201 -0
  394. package/workflow_nodes/mailjetTrigger.json +8 -0
  395. package/workflow_nodes/mandrill.json +372 -0
  396. package/workflow_nodes/manualTrigger.json +8 -0
  397. package/workflow_nodes/markdown.json +376 -0
  398. package/workflow_nodes/marketstack.json +126 -0
  399. package/workflow_nodes/matrix.json +264 -0
  400. package/workflow_nodes/mattermost.json +8 -0
  401. package/workflow_nodes/mautic.json +564 -0
  402. package/workflow_nodes/mauticTrigger.json +54 -0
  403. package/workflow_nodes/medium.json +209 -0
  404. package/workflow_nodes/merge.json +125 -0
  405. package/workflow_nodes/messageBird.json +182 -0
  406. package/workflow_nodes/metabase.json +175 -0
  407. package/workflow_nodes/microsoftDynamicsCrm.json +100 -0
  408. package/workflow_nodes/microsoftEntra.json +51 -0
  409. package/workflow_nodes/microsoftExcel.json +35 -0
  410. package/workflow_nodes/microsoftGraphSecurity.json +113 -0
  411. package/workflow_nodes/microsoftOneDrive.json +232 -0
  412. package/workflow_nodes/microsoftOneDriveTrigger.json +80 -0
  413. package/workflow_nodes/microsoftOutlook.json +40 -0
  414. package/workflow_nodes/microsoftOutlookTrigger.json +24 -0
  415. package/workflow_nodes/microsoftSql.json +81 -0
  416. package/workflow_nodes/microsoftTeams.json +36 -0
  417. package/workflow_nodes/microsoftToDo.json +181 -0
  418. package/workflow_nodes/mindee.json +86 -0
  419. package/workflow_nodes/misp.json +399 -0
  420. package/workflow_nodes/mocean.json +103 -0
  421. package/workflow_nodes/mondayCom.json +290 -0
  422. package/workflow_nodes/mongoDb.json +16 -0
  423. package/workflow_nodes/monicaCrm.json +543 -0
  424. package/workflow_nodes/moveBinaryData.json +121 -0
  425. package/workflow_nodes/mqtt.json +67 -0
  426. package/workflow_nodes/mqttTrigger.json +47 -0
  427. package/workflow_nodes/msg91.json +65 -0
  428. package/workflow_nodes/mySql.json +111 -0
  429. package/workflow_nodes/n8n.json +75 -0
  430. package/workflow_nodes/n8nTrigger.json +27 -0
  431. package/workflow_nodes/nasa.json +310 -0
  432. package/workflow_nodes/netlify.json +87 -0
  433. package/workflow_nodes/netlifyTrigger.json +68 -0
  434. package/workflow_nodes/netscalerAdc.json +243 -0
  435. package/workflow_nodes/nextCloud.json +312 -0
  436. package/workflow_nodes/noOp.json +8 -0
  437. package/workflow_nodes/nocoDb.json +276 -0
  438. package/workflow_nodes/notion.json +8 -0
  439. package/workflow_nodes/notionTrigger.json +75 -0
  440. package/workflow_nodes/npm.json +64 -0
  441. package/workflow_nodes/odoo.json +344 -0
  442. package/workflow_nodes/okta.json +97 -0
  443. package/workflow_nodes/oneSimpleApi.json +281 -0
  444. package/workflow_nodes/onfleet.json +316 -0
  445. package/workflow_nodes/onfleetTrigger.json +8 -0
  446. package/workflow_nodes/openAi.json +154 -0
  447. package/workflow_nodes/openThesaurus.json +81 -0
  448. package/workflow_nodes/openWeatherMap.json +129 -0
  449. package/workflow_nodes/orbit.json +375 -0
  450. package/workflow_nodes/oura.json +74 -0
  451. package/workflow_nodes/paddle.json +403 -0
  452. package/workflow_nodes/pagerDuty.json +351 -0
  453. package/workflow_nodes/payPal.json +196 -0
  454. package/workflow_nodes/payPalTrigger.json +40 -0
  455. package/workflow_nodes/peekalink.json +41 -0
  456. package/workflow_nodes/phantombuster.json +172 -0
  457. package/workflow_nodes/philipsHue.json +177 -0
  458. package/workflow_nodes/pipedrive.json +860 -0
  459. package/workflow_nodes/pipedriveTrigger.json +11 -0
  460. package/workflow_nodes/plivo.json +91 -0
  461. package/workflow_nodes/postHog.json +122 -0
  462. package/workflow_nodes/postbin.json +60 -0
  463. package/workflow_nodes/postgres.json +109 -0
  464. package/workflow_nodes/postgresTrigger.json +8 -0
  465. package/workflow_nodes/postmarkTrigger.json +72 -0
  466. package/workflow_nodes/profitWell.json +305 -0
  467. package/workflow_nodes/pushbullet.json +186 -0
  468. package/workflow_nodes/pushcut.json +75 -0
  469. package/workflow_nodes/pushcutTrigger.json +8 -0
  470. package/workflow_nodes/pushover.json +159 -0
  471. package/workflow_nodes/questDb.json +94 -0
  472. package/workflow_nodes/quickChart.json +188 -0
  473. package/workflow_nodes/quickbase.json +205 -0
  474. package/workflow_nodes/quickbooks.json +550 -0
  475. package/workflow_nodes/rabbitmq.json +165 -0
  476. package/workflow_nodes/rabbitmqTrigger.json +8 -0
  477. package/workflow_nodes/raindrop.json +216 -0
  478. package/workflow_nodes/readBinaryFile.json +26 -0
  479. package/workflow_nodes/readBinaryFiles.json +26 -0
  480. package/workflow_nodes/readPDF.json +31 -0
  481. package/workflow_nodes/readWriteFile.json +27 -0
  482. package/workflow_nodes/reddit.json +309 -0
  483. package/workflow_nodes/redis.json +183 -0
  484. package/workflow_nodes/redisTrigger.json +8 -0
  485. package/workflow_nodes/removeDuplicates.json +8 -0
  486. package/workflow_nodes/renameKeys.json +67 -0
  487. package/workflow_nodes/respondToWebhook.json +126 -0
  488. package/workflow_nodes/rocketchat.json +216 -0
  489. package/workflow_nodes/rssFeedRead.json +28 -0
  490. package/workflow_nodes/rssFeedReadTrigger.json +17 -0
  491. package/workflow_nodes/rundeck.json +79 -0
  492. package/workflow_nodes/s3.json +425 -0
  493. package/workflow_nodes/salesforce.json +1137 -0
  494. package/workflow_nodes/salesforceTrigger.json +122 -0
  495. package/workflow_nodes/salesmate.json +467 -0
  496. package/workflow_nodes/scheduleTrigger.json +270 -0
  497. package/workflow_nodes/seaTable.json +8 -0
  498. package/workflow_nodes/seaTableTrigger.json +87 -0
  499. package/workflow_nodes/securityScorecard.json +459 -0
  500. package/workflow_nodes/segment.json +219 -0
  501. package/workflow_nodes/sendGrid.json +359 -0
  502. package/workflow_nodes/sendy.json +225 -0
  503. package/workflow_nodes/sentryIo.json +426 -0
  504. package/workflow_nodes/serviceNow.json +544 -0
  505. package/workflow_nodes/set.json +124 -0
  506. package/workflow_nodes/shopify.json +707 -0
  507. package/workflow_nodes/shopifyTrigger.json +8 -0
  508. package/workflow_nodes/signl4.json +133 -0
  509. package/workflow_nodes/simulate.json +30 -0
  510. package/workflow_nodes/simulateTrigger.json +8 -0
  511. package/workflow_nodes/slack.json +62 -0
  512. package/workflow_nodes/slackTrigger.json +135 -0
  513. package/workflow_nodes/sms77.json +121 -0
  514. package/workflow_nodes/snowflake.json +65 -0
  515. package/workflow_nodes/sort.json +57 -0
  516. package/workflow_nodes/splitInBatches.json +30 -0
  517. package/workflow_nodes/splitOut.json +62 -0
  518. package/workflow_nodes/splunk.json +40 -0
  519. package/workflow_nodes/spontit.json +123 -0
  520. package/workflow_nodes/spotify.json +285 -0
  521. package/workflow_nodes/spreadsheetFile.json +8 -0
  522. package/workflow_nodes/sseTrigger.json +8 -0
  523. package/workflow_nodes/ssh.json +105 -0
  524. package/workflow_nodes/stackby.json +85 -0
  525. package/workflow_nodes/start.json +15 -0
  526. package/workflow_nodes/stickyNote.json +36 -0
  527. package/workflow_nodes/stopAndError.json +8 -0
  528. package/workflow_nodes/storyblok.json +138 -0
  529. package/workflow_nodes/strapi.json +138 -0
  530. package/workflow_nodes/strava.json +427 -0
  531. package/workflow_nodes/stravaTrigger.json +79 -0
  532. package/workflow_nodes/stripe.json +357 -0
  533. package/workflow_nodes/stripeTrigger.json +775 -0
  534. package/workflow_nodes/summarize.json +124 -0
  535. package/workflow_nodes/supabase.json +136 -0
  536. package/workflow_nodes/surveyMonkeyTrigger.json +160 -0
  537. package/workflow_nodes/switch.json +91 -0
  538. package/workflow_nodes/syncroMsp.json +8 -0
  539. package/workflow_nodes/taiga.json +340 -0
  540. package/workflow_nodes/taigaTrigger.json +81 -0
  541. package/workflow_nodes/tapfiliate.json +241 -0
  542. package/workflow_nodes/telegram.json +612 -0
  543. package/workflow_nodes/telegramTrigger.json +142 -0
  544. package/workflow_nodes/theHive.json +497 -0
  545. package/workflow_nodes/theHiveProject.json +8 -0
  546. package/workflow_nodes/theHiveProjectTrigger.json +162 -0
  547. package/workflow_nodes/theHiveTrigger.json +101 -0
  548. package/workflow_nodes/timescaleDb.json +95 -0
  549. package/workflow_nodes/todoist.json +285 -0
  550. package/workflow_nodes/togglTrigger.json +24 -0
  551. package/workflow_nodes/totp.json +86 -0
  552. package/workflow_nodes/travisCi.json +142 -0
  553. package/workflow_nodes/trello.json +609 -0
  554. package/workflow_nodes/trelloTrigger.json +8 -0
  555. package/workflow_nodes/twake.json +76 -0
  556. package/workflow_nodes/twilio.json +95 -0
  557. package/workflow_nodes/twilioTrigger.json +46 -0
  558. package/workflow_nodes/twist.json +376 -0
  559. package/workflow_nodes/twitter.json +40 -0
  560. package/workflow_nodes/typeformTrigger.json +62 -0
  561. package/workflow_nodes/unleashedSoftware.json +154 -0
  562. package/workflow_nodes/uplead.json +72 -0
  563. package/workflow_nodes/uproc.json +26 -0
  564. package/workflow_nodes/uptimeRobot.json +453 -0
  565. package/workflow_nodes/urlScanIo.json +113 -0
  566. package/workflow_nodes/venafiTlsProtectCloud.json +310 -0
  567. package/workflow_nodes/venafiTlsProtectCloudTrigger.json +38 -0
  568. package/workflow_nodes/venafiTlsProtectDatacenter.json +491 -0
  569. package/workflow_nodes/vero.json +158 -0
  570. package/workflow_nodes/vonage.json +125 -0
  571. package/workflow_nodes/wait.json +71 -0
  572. package/workflow_nodes/webflow.json +38 -0
  573. package/workflow_nodes/webflowTrigger.json +8 -0
  574. package/workflow_nodes/webhook.json +55 -0
  575. package/workflow_nodes/wekan.json +460 -0
  576. package/workflow_nodes/whatsApp.json +476 -0
  577. package/workflow_nodes/whatsAppTrigger.json +103 -0
  578. package/workflow_nodes/wise.json +330 -0
  579. package/workflow_nodes/wiseTrigger.json +8 -0
  580. package/workflow_nodes/wooCommerce.json +812 -0
  581. package/workflow_nodes/wooCommerceTrigger.json +8 -0
  582. package/workflow_nodes/wordpress.json +500 -0
  583. package/workflow_nodes/workableTrigger.json +51 -0
  584. package/workflow_nodes/writeBinaryFile.json +34 -0
  585. package/workflow_nodes/wufooTrigger.json +37 -0
  586. package/workflow_nodes/xero.json +530 -0
  587. package/workflow_nodes/xml.json +129 -0
  588. package/workflow_nodes/youTube.json +578 -0
  589. package/workflow_nodes/yourls.json +71 -0
  590. package/workflow_nodes/zammad.json +406 -0
  591. package/workflow_nodes/zendesk.json +526 -0
  592. package/workflow_nodes/zendeskTrigger.json +187 -0
  593. package/workflow_nodes/zohoCrm.json +721 -0
  594. package/workflow_nodes/zoom.json +507 -0
  595. package/workflow_nodes/zulip.json +371 -0
@@ -0,0 +1,674 @@
1
+ /**
2
+ * Node Management Tools
3
+ *
4
+ * Implements tools for managing nodes in n8n workflows, including:
5
+ * - Adding new nodes to existing workflows
6
+ * - Validating node parameters against node type definitions
7
+ * - Generating unique node IDs
8
+ * - Managing node positioning in workflow canvas
9
+ * - Replacing existing nodes while maintaining connections
10
+ */
11
+
12
+ const { createTool } = require('../models/tool');
13
+ const { workflowStorage } = require('../models/storage');
14
+ const { getNodesFromSource } = require('./nodeDiscovery');
15
+ const { logger } = require('../utils/logger');
16
+ const { v4: uuidv4 } = require('uuid');
17
+
18
+ // In-memory cache for node type case mapping
19
+ let NODE_TYPE_CASE_MAP = {};
20
+
21
+ /**
22
+ * Build the node type case mapping from node definitions
23
+ *
24
+ * Dynamically creates a mapping of lowercase node types to their properly cased versions
25
+ * based on the node definitions in the workflow_nodes directory.
26
+ *
27
+ * @returns {Promise<Object>} Mapping of lowercase node types to properly cased versions
28
+ */
29
+ const buildNodeTypeCaseMap = async () => {
30
+ try {
31
+ // Get all nodes from the node discovery service
32
+ const nodes = await getNodesFromSource();
33
+ if (!Array.isArray(nodes) || nodes.length === 0) {
34
+ logger.warn('No nodes found for building case map');
35
+ return {};
36
+ }
37
+
38
+ const caseMap = {};
39
+
40
+ // Process each node to build the case map
41
+ for (const node of nodes) {
42
+ if (node.originalNodeType) {
43
+ // Handle full node type (with prefix)
44
+ const lowerCaseType = node.originalNodeType.toLowerCase();
45
+ caseMap[lowerCaseType] = node.originalNodeType;
46
+
47
+ // Also add entry for the node name without prefix
48
+ if (lowerCaseType.startsWith('n8n-nodes-base.')) {
49
+ const shortName = lowerCaseType.split('n8n-nodes-base.')[1];
50
+ caseMap[shortName] = node.originalNodeType;
51
+ }
52
+ }
53
+
54
+ // Add entry for node ID if it exists
55
+ if (node.id) {
56
+ const nodeId = node.id.toLowerCase();
57
+ const nodeTypeWithPrefix = `n8n-nodes-base.${node.id}`;
58
+
59
+ // If we don't already have this mapping (original node type has precedence)
60
+ if (!caseMap[nodeId]) {
61
+ caseMap[nodeId] = nodeTypeWithPrefix;
62
+ }
63
+
64
+ // Also map the full prefixed version
65
+ const prefixedLowerCase = `n8n-nodes-base.${nodeId}`;
66
+ if (!caseMap[prefixedLowerCase]) {
67
+ caseMap[prefixedLowerCase] = nodeTypeWithPrefix;
68
+ }
69
+ }
70
+ }
71
+
72
+ logger.info(`Built node type case map with ${Object.keys(caseMap).length} entries`);
73
+ return caseMap;
74
+ } catch (error) {
75
+ logger.error('Error building node type case map:', error);
76
+ return {};
77
+ }
78
+ };
79
+
80
+ /**
81
+ * Get the properly cased node type for special cases
82
+ *
83
+ * This function handles both simple node type names (like "openai")
84
+ * and full node types (like "n8n-nodes-base.openai"), ensuring
85
+ * the proper casing is used in the workflow.
86
+ *
87
+ * @param {string} nodeType - Node type to check (with or without prefix)
88
+ * @returns {string|null} - Properly cased node type or null if no special case
89
+ */
90
+ const getSpecialCaseNodeType = async (nodeType) => {
91
+ if (!nodeType) return null;
92
+
93
+ // Ensure the case map is populated
94
+ if (Object.keys(NODE_TYPE_CASE_MAP).length === 0) {
95
+ NODE_TYPE_CASE_MAP = await buildNodeTypeCaseMap();
96
+ }
97
+
98
+ // Normalize to lowercase for lookup
99
+ const normalizedType = nodeType.toLowerCase();
100
+
101
+ // Check direct mapping first
102
+ if (NODE_TYPE_CASE_MAP[normalizedType]) {
103
+ return NODE_TYPE_CASE_MAP[normalizedType];
104
+ }
105
+
106
+ // If no direct match and no prefix, try adding the prefix
107
+ const prefix = 'n8n-nodes-base.';
108
+ if (!normalizedType.includes(prefix)) {
109
+ const withPrefix = prefix + normalizedType;
110
+ if (NODE_TYPE_CASE_MAP[withPrefix]) {
111
+ return NODE_TYPE_CASE_MAP[withPrefix];
112
+ }
113
+ }
114
+
115
+ // For backwards compatibility: try to extract node name and apply casing
116
+ if (normalizedType.startsWith(prefix)) {
117
+ const nodeName = normalizedType.replace(prefix, '');
118
+ if (NODE_TYPE_CASE_MAP[nodeName]) {
119
+ return NODE_TYPE_CASE_MAP[nodeName];
120
+ }
121
+ }
122
+
123
+ // If we don't have a specific mapping, check if we need to add the prefix
124
+ if (!normalizedType.startsWith(prefix)) {
125
+ return prefix + normalizedType;
126
+ }
127
+
128
+ // Return the original if all else fails
129
+ return nodeType;
130
+ };
131
+
132
+ // Load the node type case map on module initialization
133
+ buildNodeTypeCaseMap().then(caseMap => {
134
+ NODE_TYPE_CASE_MAP = caseMap;
135
+ }).catch(error => {
136
+ logger.error('Failed to initialize node type case map:', error);
137
+ });
138
+
139
+ /**
140
+ * Generate a unique ID for a node within a workflow
141
+ *
142
+ * @param {Object} workflow - The workflow object
143
+ * @returns {string} Unique node ID
144
+ */
145
+ const generateUniqueNodeId = (workflow) => {
146
+ // Base ID on node type or use a random string
147
+ const baseId = 'node';
148
+
149
+ // Find the highest numbered ID with this base
150
+ let maxNumber = 0;
151
+ if (workflow.nodes && Array.isArray(workflow.nodes)) {
152
+ workflow.nodes.forEach(node => {
153
+ if (node.id && node.id.startsWith(baseId)) {
154
+ const numStr = node.id.replace(baseId, '');
155
+ const num = parseInt(numStr, 10);
156
+ if (!isNaN(num) && num > maxNumber) {
157
+ maxNumber = num;
158
+ }
159
+ }
160
+ });
161
+ }
162
+
163
+ // Generate the next available ID
164
+ return `${baseId}${maxNumber + 1}`;
165
+ };
166
+
167
+ /**
168
+ * Find node type definition from available nodes
169
+ *
170
+ * @param {string} nodeType - Type of node to find
171
+ * @returns {Promise<Object|null>} Node type definition or null if not found
172
+ */
173
+ const getNodeTypeDefinition = async (nodeType) => {
174
+ const nodesData = await getNodesFromSource();
175
+ const nodes = Array.isArray(nodesData) ? nodesData : []; // Ensure we have an array
176
+ const filenameMap = nodesData.filenameMap || {}; // Get the filename map if available
177
+
178
+ // Handle case insensitive matching and potential camelCase vs lowercase inconsistencies
179
+ // First convert to lowercase for node type comparison
180
+ const normalizedNodeType = nodeType.toLowerCase();
181
+
182
+ // Check if we're looking for a node with just the node name or the full n8n-nodes-base prefix
183
+ const hasPrefix = normalizedNodeType.startsWith('n8n-nodes-base.');
184
+ let nodeNameOnly = normalizedNodeType;
185
+
186
+ if (hasPrefix) {
187
+ // If it has the prefix, extract just the node name for lookups
188
+ nodeNameOnly = normalizedNodeType.split('n8n-nodes-base.')[1];
189
+ }
190
+
191
+ // Check if we have this node name in our filename map, which preserves original casing
192
+ const originalCaseNodeName = filenameMap[nodeNameOnly];
193
+
194
+ // First try to find by exact ID match (the filename minus extension)
195
+ let matchedNode = nodes.find(node => node.id.toLowerCase() === nodeNameOnly);
196
+
197
+ // Next, if we have a prefix, try to match by the originalNodeType which has exact casing
198
+ if (!matchedNode && hasPrefix) {
199
+ matchedNode = nodes.find(node =>
200
+ node.originalNodeType && node.originalNodeType.toLowerCase() === normalizedNodeType);
201
+ }
202
+
203
+ // If still no match, try nodeType matching with originals
204
+ if (!matchedNode) {
205
+ matchedNode = nodes.find(node => {
206
+ // Check both the node ID and the file name for matches
207
+ const nodeIdMatch = node.id.toLowerCase() === nodeNameOnly;
208
+
209
+ // Check if the normalized version of the node type matches
210
+ const normalizedTypeMatch = node.normalizedType &&
211
+ nodeNameOnly === node.normalizedType;
212
+
213
+ // Check if the type fields match (case insensitive)
214
+ const nodeTypeMatch = (
215
+ (node.type && node.type.toLowerCase() === normalizedNodeType) ||
216
+ (node.originalNodeType && node.originalNodeType.toLowerCase() === normalizedNodeType) ||
217
+ (hasPrefix && node.id.toLowerCase() === nodeNameOnly)
218
+ );
219
+
220
+ return nodeIdMatch || normalizedTypeMatch || nodeTypeMatch;
221
+ });
222
+ }
223
+
224
+ // If we found a match at this point, return it
225
+ if (matchedNode) {
226
+ // Log for debugging
227
+ logger.debug(`Found node match for ${nodeType}:`, {
228
+ id: matchedNode.id,
229
+ type: matchedNode.type,
230
+ originalNodeType: matchedNode.originalNodeType
231
+ });
232
+
233
+ return matchedNode;
234
+ }
235
+
236
+ // If all else fails, do a broader search that's less precise
237
+ matchedNode = nodes.find(node => {
238
+ return node.id.toLowerCase().includes(nodeNameOnly) ||
239
+ (node.type && node.type.toLowerCase().includes(nodeNameOnly)) ||
240
+ (node.originalNodeType && node.originalNodeType.toLowerCase().includes(nodeNameOnly));
241
+ });
242
+
243
+ return matchedNode || null;
244
+ };
245
+
246
+ /**
247
+ * Validate node parameters against the node type definition
248
+ *
249
+ * @param {Object} nodeTypeDef - Node type definition
250
+ * @param {Object} parameters - Node parameters to validate
251
+ * @returns {boolean} True if valid, throws error if invalid
252
+ */
253
+ const validateNodeParameters = (nodeTypeDef, parameters) => {
254
+ if (!parameters) return true;
255
+
256
+ // For now, perform basic validation
257
+ // A more comprehensive validation would check against parameter schema
258
+
259
+ // Check that all required parameters are present
260
+ const requiredParams = nodeTypeDef.parameters
261
+ .filter(param => param.required)
262
+ .map(param => param.name);
263
+
264
+ const missingParams = requiredParams.filter(name =>
265
+ !parameters.hasOwnProperty(name)
266
+ );
267
+
268
+ if (missingParams.length > 0) {
269
+ throw new Error(`Missing required parameters: ${missingParams.join(', ')}`);
270
+ }
271
+
272
+ return true;
273
+ };
274
+
275
+ /**
276
+ * Check if connections between two node types are compatible
277
+ *
278
+ * @param {Object} originalNodeDef - Original node definition
279
+ * @param {Object} newNodeDef - New node definition
280
+ * @returns {Object} Compatibility assessment with input and output compatibility
281
+ */
282
+ const checkConnectionCompatibility = (originalNodeDef, newNodeDef) => {
283
+ // Default to uncertain compatibility if we can't determine
284
+ const defaultCompatibility = {
285
+ inputCompatible: true,
286
+ outputCompatible: true,
287
+ warnings: []
288
+ };
289
+
290
+ // If either definition is missing, we can't make a determination
291
+ if (!originalNodeDef || !newNodeDef) {
292
+ return {
293
+ inputCompatible: true, // Assume compatible for safety
294
+ outputCompatible: true, // Assume compatible for safety
295
+ warnings: ['Could not determine connection compatibility due to missing node definitions']
296
+ };
297
+ }
298
+
299
+ // Start with simple category compatibility checks
300
+ const originalCategories = new Set(originalNodeDef.categories || []);
301
+ const newCategories = new Set(newNodeDef.categories || []);
302
+
303
+ const compatibility = {
304
+ inputCompatible: true,
305
+ outputCompatible: true,
306
+ warnings: []
307
+ };
308
+
309
+ // If original was a trigger and new is not, that's an incompatibility
310
+ if (originalCategories.has('Trigger') && !newCategories.has('Trigger')) {
311
+ compatibility.inputCompatible = false;
312
+ compatibility.warnings.push('Original node was a Trigger but new node is not');
313
+ }
314
+
315
+ // Parameter structure incompatibility check (basic)
316
+ const originalParamCount = originalNodeDef.parameters?.length || 0;
317
+ const newParamCount = newNodeDef.parameters?.length || 0;
318
+
319
+ if (originalParamCount > newParamCount + 5) {
320
+ compatibility.warnings.push('New node has significantly fewer parameters than original node');
321
+ }
322
+
323
+ return compatibility;
324
+ };
325
+
326
+ /**
327
+ * Update connections for replaced node based on compatibility
328
+ *
329
+ * @param {Object} workflow - The workflow object
330
+ * @param {string} nodeId - ID of the replaced node
331
+ * @param {string} originalNodeType - Original node type
332
+ * @param {string} newNodeType - New node type
333
+ * @returns {Object} Updated workflow with adjusted connections
334
+ */
335
+ const updateConnectionsForReplacedNode = async (workflow, nodeId, originalNodeType, newNodeType) => {
336
+ // Get node definitions for checking compatibility using the updated case-insensitive matching
337
+ // The original node type might have camelCase that needs to be handled
338
+ const originalNodeDef = await getNodeTypeDefinition(originalNodeType);
339
+ const newNodeDef = await getNodeTypeDefinition(newNodeType);
340
+
341
+ // Check connection compatibility
342
+ const compatibility = checkConnectionCompatibility(originalNodeDef, newNodeDef);
343
+
344
+ // If no connections to modify or we're keeping all, return as is
345
+ if (!workflow.connections || !Array.isArray(workflow.connections)) {
346
+ return {
347
+ workflow,
348
+ compatibility
349
+ };
350
+ }
351
+
352
+ // Check each connection
353
+ if (!compatibility.inputCompatible || !compatibility.outputCompatible) {
354
+ // Filter connections that need adjustment
355
+ workflow.connections = workflow.connections.filter(connection => {
356
+ // If this node is the source and output compatibility is false, remove
357
+ if (connection.source.node === nodeId && !compatibility.outputCompatible) {
358
+ return false;
359
+ }
360
+
361
+ // If this node is the target and input compatibility is false, remove
362
+ if (connection.target.node === nodeId && !compatibility.inputCompatible) {
363
+ return false;
364
+ }
365
+
366
+ return true;
367
+ });
368
+ }
369
+
370
+ return {
371
+ workflow,
372
+ compatibility
373
+ };
374
+ };
375
+
376
+ /**
377
+ * Add a node to an existing workflow
378
+ *
379
+ * @param {Object} params - The parameters for the operation
380
+ * @param {string} params.workflowId - ID or path of the workflow to modify
381
+ * @param {string} params.nodeType - Type of node to add
382
+ * @param {Object} params.position - Position on the canvas {x, y}
383
+ * @param {Object} params.parameters - Node parameters
384
+ * @returns {Promise<Object>} Operation result with updated workflow
385
+ */
386
+ const addNode = async (params) => {
387
+ try {
388
+ const { workflowId, nodeType, position, parameters, nodeName } = params;
389
+ logger.info('Adding node to workflow', { workflowId, nodeType });
390
+
391
+ // Load workflow
392
+ const workflow = await workflowStorage.loadWorkflow(workflowId);
393
+ if (!workflow) {
394
+ throw new Error(`Workflow with ID ${workflowId} not found`);
395
+ }
396
+
397
+ // Initialize nodes array if it doesn't exist
398
+ if (!workflow.nodes) {
399
+ workflow.nodes = [];
400
+ }
401
+
402
+ // Get node type definition with case-insensitive matching
403
+ const nodeTypeDef = await getNodeTypeDefinition(nodeType);
404
+ if (!nodeTypeDef) {
405
+ throw new Error(`Node type ${nodeType} not found`);
406
+ }
407
+
408
+ // Log for debugging
409
+ logger.info('Node definition found:', {
410
+ id: nodeTypeDef.id,
411
+ type: nodeTypeDef.type,
412
+ originalNodeType: nodeTypeDef.originalNodeType,
413
+ normalizedType: nodeTypeDef.normalizedType,
414
+ fileName: nodeTypeDef.fileName
415
+ });
416
+
417
+ // Validate parameters against node type definition
418
+ validateNodeParameters(nodeTypeDef, parameters);
419
+
420
+ // Generate unique node ID
421
+ const nodeId = generateUniqueNodeId(workflow);
422
+
423
+ // Use the original node type format from the definition when available
424
+ // This preserves the exact casing as in the node definition file
425
+ // which is important for proper node type resolution in n8n
426
+ let actualNodeType;
427
+
428
+ // First check for special case node types that need specific casing
429
+ const specialCaseNodeType = await getSpecialCaseNodeType(nodeType);
430
+ if (specialCaseNodeType) {
431
+ actualNodeType = specialCaseNodeType;
432
+ logger.info(`Special case handling for ${nodeType}, using: ${actualNodeType}`);
433
+ }
434
+ // Check if the nodeType is directly found in the node definition
435
+ else if (nodeTypeDef.originalNodeType) {
436
+ actualNodeType = nodeTypeDef.originalNodeType; // Use exact casing from JSON file
437
+ logger.info(`Using originalNodeType: ${actualNodeType}`);
438
+ } else if (nodeTypeDef.type) {
439
+ actualNodeType = nodeTypeDef.type;
440
+ logger.info(`Using type from node definition: ${actualNodeType}`);
441
+ } else if (nodeTypeDef.id) {
442
+ // If we have node ID but no type, reconstruct it with prefix
443
+ actualNodeType = `n8n-nodes-base.${nodeTypeDef.id}`;
444
+ logger.info(`Reconstructed from ID: ${actualNodeType}`);
445
+ } else {
446
+ // Fallback to user provided type
447
+ actualNodeType = nodeType;
448
+ logger.info(`Using original nodeType: ${actualNodeType}`);
449
+ }
450
+
451
+ // Create node object
452
+ const newNode = {
453
+ id: nodeId,
454
+ name: nodeName || nodeTypeDef.name || nodeType,
455
+ type: actualNodeType,
456
+ position: position || { x: 100, y: 100 },
457
+ parameters: parameters || {},
458
+ typeVersion: nodeTypeDef.typeVersion || 1
459
+ };
460
+
461
+ // Add node to workflow
462
+ workflow.nodes.push(newNode);
463
+
464
+ // Update workflow timestamp
465
+ workflow.updatedAt = new Date().toISOString();
466
+
467
+ // Save updated workflow to the same file
468
+ // The filePath should be extracted from the workflowId if it's already a path
469
+ const filePath = workflowId.includes('/') || workflowId.includes('\\') ?
470
+ workflowId : `${workflowId}.json`;
471
+
472
+ await workflowStorage.saveWorkflow(workflow.id || 'workflow', workflow, filePath);
473
+
474
+ return {
475
+ success: true,
476
+ nodeId,
477
+ workflow,
478
+ message: `Node ${nodeId} added successfully to workflow`
479
+ };
480
+ } catch (error) {
481
+ logger.error('Error adding node to workflow', { error: error.message });
482
+ throw new Error(`Failed to add node: ${error.message}`);
483
+ }
484
+ };
485
+
486
+ /**
487
+ * Replace a node in an existing workflow
488
+ *
489
+ * @param {Object} params - The parameters for the operation
490
+ * @param {string} params.workflowId - ID or path of the workflow to modify
491
+ * @param {string} params.targetNodeId - ID of the node to replace
492
+ * @param {string} params.newNodeType - Type of the new node
493
+ * @param {Object} params.parameters - Parameters for the new node
494
+ * @param {string} [params.nodeName] - Optional custom name for the node
495
+ * @returns {Promise<Object>} Operation result with updated workflow
496
+ */
497
+ const replaceNode = async (params) => {
498
+ try {
499
+ const { workflowId, targetNodeId, newNodeType, parameters, nodeName } = params;
500
+ logger.info('Replacing node in workflow', { workflowId, targetNodeId, newNodeType });
501
+
502
+ // Load workflow
503
+ const workflow = await workflowStorage.loadWorkflow(workflowId);
504
+ if (!workflow) {
505
+ throw new Error(`Workflow with ID ${workflowId} not found`);
506
+ }
507
+
508
+ // Find target node
509
+ const targetNodeIndex = workflow.nodes.findIndex(node => node.id === targetNodeId);
510
+ if (targetNodeIndex === -1) {
511
+ throw new Error(`Node with ID ${targetNodeId} not found in workflow`);
512
+ }
513
+
514
+ // Get node type definition with case-insensitive matching
515
+ const nodeTypeDef = await getNodeTypeDefinition(newNodeType);
516
+ if (!nodeTypeDef) {
517
+ throw new Error(`Node type ${newNodeType} not found`);
518
+ }
519
+
520
+ // Store original node for compatibility checking
521
+ const originalNode = workflow.nodes[targetNodeIndex];
522
+ const originalNodeType = originalNode.type;
523
+
524
+ // Validate parameters against node type definition
525
+ validateNodeParameters(nodeTypeDef, parameters);
526
+
527
+ // Use the original node type format from the definition when available
528
+ // This preserves the exact casing as in the node definition file
529
+ let actualNodeType;
530
+
531
+ // First check for special case node types that need specific casing
532
+ const specialCaseNodeType = await getSpecialCaseNodeType(newNodeType);
533
+ if (specialCaseNodeType) {
534
+ actualNodeType = specialCaseNodeType;
535
+ logger.info(`Special case handling for ${newNodeType}, using: ${actualNodeType}`);
536
+ }
537
+ // Check if the nodeType is directly found in the node definition
538
+ else if (nodeTypeDef.originalNodeType) {
539
+ actualNodeType = nodeTypeDef.originalNodeType; // Use exact casing from JSON file
540
+ logger.info(`Using originalNodeType: ${actualNodeType}`);
541
+ } else if (nodeTypeDef.type) {
542
+ actualNodeType = nodeTypeDef.type;
543
+ logger.info(`Using type from node definition: ${actualNodeType}`);
544
+ } else if (nodeTypeDef.id) {
545
+ // If we have node ID but no type, reconstruct it with prefix
546
+ actualNodeType = `n8n-nodes-base.${nodeTypeDef.id}`;
547
+ logger.info(`Reconstructed from ID: ${actualNodeType}`);
548
+ } else {
549
+ // Fallback to user provided type
550
+ actualNodeType = newNodeType;
551
+ logger.info(`Using original nodeType: ${actualNodeType}`);
552
+ }
553
+
554
+ // Create new node object, maintaining position and ID
555
+ const newNode = {
556
+ id: targetNodeId, // Keep same ID to maintain connections
557
+ name: nodeName || nodeTypeDef.name || newNodeType,
558
+ type: actualNodeType,
559
+ position: originalNode.position,
560
+ parameters: parameters || {},
561
+ typeVersion: nodeTypeDef.typeVersion || 1
562
+ };
563
+
564
+ // Replace node in workflow
565
+ workflow.nodes[targetNodeIndex] = newNode;
566
+
567
+ // Update workflow timestamp
568
+ workflow.updatedAt = new Date().toISOString();
569
+
570
+ // Check connection compatibility and adjust connections if needed
571
+ const { workflow: updatedWorkflow, compatibility } =
572
+ await updateConnectionsForReplacedNode(workflow, targetNodeId, originalNodeType, newNodeType);
573
+
574
+ // Save updated workflow
575
+ const filePath = workflowId.includes('/') || workflowId.includes('\\') ?
576
+ workflowId : `${workflowId}.json`;
577
+
578
+ await workflowStorage.saveWorkflow(updatedWorkflow.id || 'workflow', updatedWorkflow, filePath);
579
+
580
+ return {
581
+ success: true,
582
+ nodeId: targetNodeId,
583
+ workflow: updatedWorkflow,
584
+ compatibility: compatibility.warnings, // Include compatibility warnings in response
585
+ message: `Node ${targetNodeId} replaced successfully with ${newNodeType}`
586
+ };
587
+ } catch (error) {
588
+ logger.error('Error replacing node in workflow', { error: error.message });
589
+ throw new Error(`Failed to replace node: ${error.message}`);
590
+ }
591
+ };
592
+
593
+ /**
594
+ * Tool definition for the add_node MCP tool
595
+ */
596
+ const addNodeTool = createTool(
597
+ 'Add a node to an existing workflow',
598
+ {
599
+ workflowId: {
600
+ type: 'string',
601
+ description: 'ID or path of the workflow to add the node to'
602
+ },
603
+ nodeType: {
604
+ type: 'string',
605
+ description: 'Type of node to add (e.g., "gmail", "slack", "openai"). Use the list_available_nodes tool to see all available nodes with their correct casing. The system will automatically handle proper casing and prefixing for you.'
606
+ },
607
+ nodeName: {
608
+ type: 'string',
609
+ description: 'Custom display name for the node in the workflow',
610
+ optional: true
611
+ },
612
+ position: {
613
+ type: 'object',
614
+ description: 'Position of the node in the workflow canvas',
615
+ properties: {
616
+ x: { type: 'number' },
617
+ y: { type: 'number' }
618
+ },
619
+ optional: true
620
+ },
621
+ parameters: {
622
+ type: 'object',
623
+ description: 'Parameters for the node',
624
+ optional: true
625
+ }
626
+ },
627
+ addNode
628
+ );
629
+
630
+ /**
631
+ * Tool definition for the replace_node MCP tool
632
+ */
633
+ const replaceNodeTool = createTool(
634
+ 'Replace an existing node in a workflow with a new node type while maintaining connections where possible',
635
+ {
636
+ workflowId: {
637
+ type: 'string',
638
+ description: 'ID or path of the workflow containing the node'
639
+ },
640
+ targetNodeId: {
641
+ type: 'string',
642
+ description: 'ID of the node to replace'
643
+ },
644
+ newNodeType: {
645
+ type: 'string',
646
+ description: 'Type of node to replace with (e.g., "gmail", "slack", "openai"). Use the list_available_nodes tool to see all available nodes with their correct casing. The system will automatically handle proper casing and prefixing for you.'
647
+ },
648
+ nodeName: {
649
+ type: 'string',
650
+ description: 'Custom display name for the new node in the workflow',
651
+ optional: true
652
+ },
653
+ parameters: {
654
+ type: 'object',
655
+ description: 'Parameters for the new node',
656
+ optional: true
657
+ }
658
+ },
659
+ replaceNode
660
+ );
661
+
662
+ module.exports = {
663
+ addNodeTool,
664
+ replaceNodeTool,
665
+ addNode,
666
+ replaceNode,
667
+ generateUniqueNodeId,
668
+ getNodeTypeDefinition,
669
+ validateNodeParameters,
670
+ checkConnectionCompatibility,
671
+ updateConnectionsForReplacedNode,
672
+ getSpecialCaseNodeType,
673
+ buildNodeTypeCaseMap
674
+ };