This is page 1 of 46. Use http://codebase.md/czlonkowski/n8n-mcp?page={x} to view the full context. # Directory Structure ``` ├── _config.yml ├── .claude │ └── agents │ ├── code-reviewer.md │ ├── context-manager.md │ ├── debugger.md │ ├── deployment-engineer.md │ ├── mcp-backend-engineer.md │ ├── n8n-mcp-tester.md │ ├── technical-researcher.md │ └── test-automator.md ├── .dockerignore ├── .env.docker ├── .env.example ├── .env.n8n.example ├── .env.test ├── .env.test.example ├── .github │ ├── ABOUT.md │ ├── BENCHMARK_THRESHOLDS.md │ ├── FUNDING.yml │ ├── gh-pages.yml │ ├── secret_scanning.yml │ └── workflows │ ├── benchmark-pr.yml │ ├── benchmark.yml │ ├── docker-build-fast.yml │ ├── docker-build-n8n.yml │ ├── docker-build.yml │ ├── release.yml │ ├── test.yml │ └── update-n8n-deps.yml ├── .gitignore ├── .npmignore ├── ATTRIBUTION.md ├── CHANGELOG.md ├── CLAUDE.md ├── codecov.yml ├── coverage.json ├── data │ ├── .gitkeep │ ├── nodes.db │ ├── nodes.db-shm │ ├── nodes.db-wal │ └── templates.db ├── deploy │ └── quick-deploy-n8n.sh ├── docker │ ├── docker-entrypoint.sh │ ├── n8n-mcp │ ├── parse-config.js │ └── README.md ├── docker-compose.buildkit.yml ├── docker-compose.extract.yml ├── docker-compose.n8n.yml ├── docker-compose.override.yml.example ├── docker-compose.test-n8n.yml ├── docker-compose.yml ├── Dockerfile ├── Dockerfile.railway ├── Dockerfile.test ├── docs │ ├── AUTOMATED_RELEASES.md │ ├── BENCHMARKS.md │ ├── bugfix-onSessionCreated-event.md │ ├── CHANGELOG.md │ ├── CLAUDE_CODE_SETUP.md │ ├── CLAUDE_INTERVIEW.md │ ├── CODECOV_SETUP.md │ ├── CODEX_SETUP.md │ ├── CURSOR_SETUP.md │ ├── DEPENDENCY_UPDATES.md │ ├── DOCKER_README.md │ ├── DOCKER_TROUBLESHOOTING.md │ ├── FINAL_AI_VALIDATION_SPEC.md │ ├── FLEXIBLE_INSTANCE_CONFIGURATION.md │ ├── HTTP_DEPLOYMENT.md │ ├── img │ │ ├── cc_command.png │ │ ├── cc_connected.png │ │ ├── codex_connected.png │ │ ├── cursor_tut.png │ │ ├── Railway_api.png │ │ ├── Railway_server_address.png │ │ ├── vsc_ghcp_chat_agent_mode.png │ │ ├── vsc_ghcp_chat_instruction_files.png │ │ ├── vsc_ghcp_chat_thinking_tool.png │ │ └── windsurf_tut.png │ ├── INSTALLATION.md │ ├── LIBRARY_USAGE.md │ ├── local │ │ ├── DEEP_DIVE_ANALYSIS_2025-10-02.md │ │ ├── DEEP_DIVE_ANALYSIS_README.md │ │ ├── Deep_dive_p1_p2.md │ │ ├── integration-testing-plan.md │ │ ├── integration-tests-phase1-summary.md │ │ ├── N8N_AI_WORKFLOW_BUILDER_ANALYSIS.md │ │ ├── P0_IMPLEMENTATION_PLAN.md │ │ └── TEMPLATE_MINING_ANALYSIS.md │ ├── MCP_ESSENTIALS_README.md │ ├── MCP_QUICK_START_GUIDE.md │ ├── N8N_DEPLOYMENT.md │ ├── RAILWAY_DEPLOYMENT.md │ ├── README_CLAUDE_SETUP.md │ ├── README.md │ ├── tools-documentation-usage.md │ ├── VS_CODE_PROJECT_SETUP.md │ ├── WINDSURF_SETUP.md │ └── workflow-diff-examples.md ├── examples │ └── enhanced-documentation-demo.js ├── fetch_log.txt ├── IMPLEMENTATION_GUIDE.md ├── LICENSE ├── MEMORY_N8N_UPDATE.md ├── MEMORY_TEMPLATE_UPDATE.md ├── monitor_fetch.sh ├── MVP_DEPLOYMENT_PLAN.md ├── N8N_HTTP_STREAMABLE_SETUP.md ├── n8n-nodes.db ├── P0-R3-TEST-PLAN.md ├── package-lock.json ├── package.json ├── package.runtime.json ├── PRIVACY.md ├── railway.json ├── README.md ├── renovate.json ├── scripts │ ├── analyze-optimization.sh │ ├── audit-schema-coverage.ts │ ├── build-optimized.sh │ ├── compare-benchmarks.js │ ├── demo-optimization.sh │ ├── deploy-http.sh │ ├── deploy-to-vm.sh │ ├── export-webhook-workflows.ts │ ├── extract-changelog.js │ ├── extract-from-docker.js │ ├── extract-nodes-docker.sh │ ├── extract-nodes-simple.sh │ ├── format-benchmark-results.js │ ├── generate-benchmark-stub.js │ ├── generate-detailed-reports.js │ ├── generate-test-summary.js │ ├── http-bridge.js │ ├── mcp-http-client.js │ ├── migrate-nodes-fts.ts │ ├── migrate-tool-docs.ts │ ├── n8n-docs-mcp.service │ ├── nginx-n8n-mcp.conf │ ├── prebuild-fts5.ts │ ├── prepare-release.js │ ├── publish-npm-quick.sh │ ├── publish-npm.sh │ ├── quick-test.ts │ ├── run-benchmarks-ci.js │ ├── sync-runtime-version.js │ ├── test-ai-validation-debug.ts │ ├── test-code-node-enhancements.ts │ ├── test-code-node-fixes.ts │ ├── test-docker-config.sh │ ├── test-docker-fingerprint.ts │ ├── test-docker-optimization.sh │ ├── test-docker.sh │ ├── test-empty-connection-validation.ts │ ├── test-error-message-tracking.ts │ ├── test-error-output-validation.ts │ ├── test-error-validation.js │ ├── test-essentials.ts │ ├── test-expression-code-validation.ts │ ├── test-expression-format-validation.js │ ├── test-fts5-search.ts │ ├── test-fuzzy-fix.ts │ ├── test-fuzzy-simple.ts │ ├── test-helpers-validation.ts │ ├── test-http-search.ts │ ├── test-http.sh │ ├── test-jmespath-validation.ts │ ├── test-multi-tenant-simple.ts │ ├── test-multi-tenant.ts │ ├── test-n8n-integration.sh │ ├── test-node-info.js │ ├── test-node-type-validation.ts │ ├── test-nodes-base-prefix.ts │ ├── test-operation-validation.ts │ ├── test-optimized-docker.sh │ ├── test-release-automation.js │ ├── test-search-improvements.ts │ ├── test-security.ts │ ├── test-single-session.sh │ ├── test-sqljs-triggers.ts │ ├── test-telemetry-debug.ts │ ├── test-telemetry-direct.ts │ ├── test-telemetry-env.ts │ ├── test-telemetry-integration.ts │ ├── test-telemetry-no-select.ts │ ├── test-telemetry-security.ts │ ├── test-telemetry-simple.ts │ ├── test-typeversion-validation.ts │ ├── test-url-configuration.ts │ ├── test-user-id-persistence.ts │ ├── test-webhook-validation.ts │ ├── test-workflow-insert.ts │ ├── test-workflow-sanitizer.ts │ ├── test-workflow-tracking-debug.ts │ ├── update-and-publish-prep.sh │ ├── update-n8n-deps.js │ ├── update-readme-version.js │ ├── vitest-benchmark-json-reporter.js │ └── vitest-benchmark-reporter.ts ├── SECURITY.md ├── src │ ├── config │ │ └── n8n-api.ts │ ├── data │ │ └── canonical-ai-tool-examples.json │ ├── database │ │ ├── database-adapter.ts │ │ ├── migrations │ │ │ └── add-template-node-configs.sql │ │ ├── node-repository.ts │ │ ├── nodes.db │ │ ├── schema-optimized.sql │ │ └── schema.sql │ ├── errors │ │ └── validation-service-error.ts │ ├── http-server-single-session.ts │ ├── http-server.ts │ ├── index.ts │ ├── loaders │ │ └── node-loader.ts │ ├── mappers │ │ └── docs-mapper.ts │ ├── mcp │ │ ├── handlers-n8n-manager.ts │ │ ├── handlers-workflow-diff.ts │ │ ├── index.ts │ │ ├── server.ts │ │ ├── stdio-wrapper.ts │ │ ├── tool-docs │ │ │ ├── configuration │ │ │ │ ├── get-node-as-tool-info.ts │ │ │ │ ├── get-node-documentation.ts │ │ │ │ ├── get-node-essentials.ts │ │ │ │ ├── get-node-info.ts │ │ │ │ ├── get-property-dependencies.ts │ │ │ │ ├── index.ts │ │ │ │ └── search-node-properties.ts │ │ │ ├── discovery │ │ │ │ ├── get-database-statistics.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-ai-tools.ts │ │ │ │ ├── list-nodes.ts │ │ │ │ └── search-nodes.ts │ │ │ ├── guides │ │ │ │ ├── ai-agents-guide.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── system │ │ │ │ ├── index.ts │ │ │ │ ├── n8n-diagnostic.ts │ │ │ │ ├── n8n-health-check.ts │ │ │ │ ├── n8n-list-available-tools.ts │ │ │ │ └── tools-documentation.ts │ │ │ ├── templates │ │ │ │ ├── get-template.ts │ │ │ │ ├── get-templates-for-task.ts │ │ │ │ ├── index.ts │ │ │ │ ├── list-node-templates.ts │ │ │ │ ├── list-tasks.ts │ │ │ │ ├── search-templates-by-metadata.ts │ │ │ │ └── search-templates.ts │ │ │ ├── types.ts │ │ │ ├── validation │ │ │ │ ├── index.ts │ │ │ │ ├── validate-node-minimal.ts │ │ │ │ ├── validate-node-operation.ts │ │ │ │ ├── validate-workflow-connections.ts │ │ │ │ ├── validate-workflow-expressions.ts │ │ │ │ └── validate-workflow.ts │ │ │ └── workflow_management │ │ │ ├── index.ts │ │ │ ├── n8n-autofix-workflow.ts │ │ │ ├── n8n-create-workflow.ts │ │ │ ├── n8n-delete-execution.ts │ │ │ ├── n8n-delete-workflow.ts │ │ │ ├── n8n-get-execution.ts │ │ │ ├── n8n-get-workflow-details.ts │ │ │ ├── n8n-get-workflow-minimal.ts │ │ │ ├── n8n-get-workflow-structure.ts │ │ │ ├── n8n-get-workflow.ts │ │ │ ├── n8n-list-executions.ts │ │ │ ├── n8n-list-workflows.ts │ │ │ ├── n8n-trigger-webhook-workflow.ts │ │ │ ├── n8n-update-full-workflow.ts │ │ │ ├── n8n-update-partial-workflow.ts │ │ │ └── n8n-validate-workflow.ts │ │ ├── tools-documentation.ts │ │ ├── tools-n8n-friendly.ts │ │ ├── tools-n8n-manager.ts │ │ ├── tools.ts │ │ └── workflow-examples.ts │ ├── mcp-engine.ts │ ├── mcp-tools-engine.ts │ ├── n8n │ │ ├── MCPApi.credentials.ts │ │ └── MCPNode.node.ts │ ├── parsers │ │ ├── node-parser.ts │ │ ├── property-extractor.ts │ │ └── simple-parser.ts │ ├── scripts │ │ ├── debug-http-search.ts │ │ ├── extract-from-docker.ts │ │ ├── fetch-templates-robust.ts │ │ ├── fetch-templates.ts │ │ ├── rebuild-database.ts │ │ ├── rebuild-optimized.ts │ │ ├── rebuild.ts │ │ ├── sanitize-templates.ts │ │ ├── seed-canonical-ai-examples.ts │ │ ├── test-autofix-documentation.ts │ │ ├── test-autofix-workflow.ts │ │ ├── test-execution-filtering.ts │ │ ├── test-node-suggestions.ts │ │ ├── test-protocol-negotiation.ts │ │ ├── test-summary.ts │ │ ├── test-webhook-autofix.ts │ │ ├── validate.ts │ │ └── validation-summary.ts │ ├── services │ │ ├── ai-node-validator.ts │ │ ├── ai-tool-validators.ts │ │ ├── confidence-scorer.ts │ │ ├── config-validator.ts │ │ ├── enhanced-config-validator.ts │ │ ├── example-generator.ts │ │ ├── execution-processor.ts │ │ ├── expression-format-validator.ts │ │ ├── expression-validator.ts │ │ ├── n8n-api-client.ts │ │ ├── n8n-validation.ts │ │ ├── node-documentation-service.ts │ │ ├── node-similarity-service.ts │ │ ├── node-specific-validators.ts │ │ ├── operation-similarity-service.ts │ │ ├── property-dependencies.ts │ │ ├── property-filter.ts │ │ ├── resource-similarity-service.ts │ │ ├── sqlite-storage-service.ts │ │ ├── task-templates.ts │ │ ├── universal-expression-validator.ts │ │ ├── workflow-auto-fixer.ts │ │ ├── workflow-diff-engine.ts │ │ └── workflow-validator.ts │ ├── telemetry │ │ ├── batch-processor.ts │ │ ├── config-manager.ts │ │ ├── early-error-logger.ts │ │ ├── error-sanitization-utils.ts │ │ ├── error-sanitizer.ts │ │ ├── event-tracker.ts │ │ ├── event-validator.ts │ │ ├── index.ts │ │ ├── performance-monitor.ts │ │ ├── rate-limiter.ts │ │ ├── startup-checkpoints.ts │ │ ├── telemetry-error.ts │ │ ├── telemetry-manager.ts │ │ ├── telemetry-types.ts │ │ └── workflow-sanitizer.ts │ ├── templates │ │ ├── batch-processor.ts │ │ ├── metadata-generator.ts │ │ ├── README.md │ │ ├── template-fetcher.ts │ │ ├── template-repository.ts │ │ └── template-service.ts │ ├── types │ │ ├── index.ts │ │ ├── instance-context.ts │ │ ├── n8n-api.ts │ │ ├── node-types.ts │ │ ├── session-restoration.ts │ │ └── workflow-diff.ts │ └── utils │ ├── auth.ts │ ├── bridge.ts │ ├── cache-utils.ts │ ├── console-manager.ts │ ├── documentation-fetcher.ts │ ├── enhanced-documentation-fetcher.ts │ ├── error-handler.ts │ ├── example-generator.ts │ ├── fixed-collection-validator.ts │ ├── logger.ts │ ├── mcp-client.ts │ ├── n8n-errors.ts │ ├── node-source-extractor.ts │ ├── node-type-normalizer.ts │ ├── node-type-utils.ts │ ├── node-utils.ts │ ├── npm-version-checker.ts │ ├── protocol-version.ts │ ├── simple-cache.ts │ ├── ssrf-protection.ts │ ├── template-node-resolver.ts │ ├── template-sanitizer.ts │ ├── url-detector.ts │ ├── validation-schemas.ts │ └── version.ts ├── supabase-telemetry-aggregation.sql ├── TELEMETRY_PRUNING_GUIDE.md ├── telemetry-pruning-analysis.md ├── test-output.txt ├── test-reinit-fix.sh ├── tests │ ├── __snapshots__ │ │ └── .gitkeep │ ├── auth.test.ts │ ├── benchmarks │ │ ├── database-queries.bench.ts │ │ ├── index.ts │ │ ├── mcp-tools.bench.ts │ │ ├── mcp-tools.bench.ts.disabled │ │ ├── mcp-tools.bench.ts.skip │ │ ├── node-loading.bench.ts.disabled │ │ ├── README.md │ │ ├── search-operations.bench.ts.disabled │ │ └── validation-performance.bench.ts.disabled │ ├── bridge.test.ts │ ├── comprehensive-extraction-test.js │ ├── data │ │ └── .gitkeep │ ├── debug-slack-doc.js │ ├── demo-enhanced-documentation.js │ ├── docker-tests-README.md │ ├── error-handler.test.ts │ ├── examples │ │ └── using-database-utils.test.ts │ ├── extracted-nodes-db │ │ ├── database-import.json │ │ ├── extraction-report.json │ │ ├── insert-nodes.sql │ │ ├── n8n-nodes-base__Airtable.json │ │ ├── n8n-nodes-base__Discord.json │ │ ├── n8n-nodes-base__Function.json │ │ ├── n8n-nodes-base__HttpRequest.json │ │ ├── n8n-nodes-base__If.json │ │ ├── n8n-nodes-base__Slack.json │ │ ├── n8n-nodes-base__SplitInBatches.json │ │ └── n8n-nodes-base__Webhook.json │ ├── factories │ │ ├── node-factory.ts │ │ └── property-definition-factory.ts │ ├── fixtures │ │ ├── .gitkeep │ │ ├── database │ │ │ └── test-nodes.json │ │ ├── factories │ │ │ ├── node.factory.ts │ │ │ └── parser-node.factory.ts │ │ └── template-configs.ts │ ├── helpers │ │ └── env-helpers.ts │ ├── http-server-auth.test.ts │ ├── integration │ │ ├── ai-validation │ │ │ ├── ai-agent-validation.test.ts │ │ │ ├── ai-tool-validation.test.ts │ │ │ ├── chat-trigger-validation.test.ts │ │ │ ├── e2e-validation.test.ts │ │ │ ├── helpers.ts │ │ │ ├── llm-chain-validation.test.ts │ │ │ ├── README.md │ │ │ └── TEST_REPORT.md │ │ ├── ci │ │ │ └── database-population.test.ts │ │ ├── database │ │ │ ├── connection-management.test.ts │ │ │ ├── empty-database.test.ts │ │ │ ├── fts5-search.test.ts │ │ │ ├── node-fts5-search.test.ts │ │ │ ├── node-repository.test.ts │ │ │ ├── performance.test.ts │ │ │ ├── template-node-configs.test.ts │ │ │ ├── template-repository.test.ts │ │ │ ├── test-utils.ts │ │ │ └── transactions.test.ts │ │ ├── database-integration.test.ts │ │ ├── docker │ │ │ ├── docker-config.test.ts │ │ │ ├── docker-entrypoint.test.ts │ │ │ └── test-helpers.ts │ │ ├── flexible-instance-config.test.ts │ │ ├── mcp │ │ │ └── template-examples-e2e.test.ts │ │ ├── mcp-protocol │ │ │ ├── basic-connection.test.ts │ │ │ ├── error-handling.test.ts │ │ │ ├── performance.test.ts │ │ │ ├── protocol-compliance.test.ts │ │ │ ├── README.md │ │ │ ├── session-management.test.ts │ │ │ ├── test-helpers.ts │ │ │ ├── tool-invocation.test.ts │ │ │ └── workflow-error-validation.test.ts │ │ ├── msw-setup.test.ts │ │ ├── n8n-api │ │ │ ├── executions │ │ │ │ ├── delete-execution.test.ts │ │ │ │ ├── get-execution.test.ts │ │ │ │ ├── list-executions.test.ts │ │ │ │ └── trigger-webhook.test.ts │ │ │ ├── scripts │ │ │ │ └── cleanup-orphans.ts │ │ │ ├── system │ │ │ │ ├── diagnostic.test.ts │ │ │ │ ├── health-check.test.ts │ │ │ │ └── list-tools.test.ts │ │ │ ├── test-connection.ts │ │ │ ├── types │ │ │ │ └── mcp-responses.ts │ │ │ ├── utils │ │ │ │ ├── cleanup-helpers.ts │ │ │ │ ├── credentials.ts │ │ │ │ ├── factories.ts │ │ │ │ ├── fixtures.ts │ │ │ │ ├── mcp-context.ts │ │ │ │ ├── n8n-client.ts │ │ │ │ ├── node-repository.ts │ │ │ │ ├── response-types.ts │ │ │ │ ├── test-context.ts │ │ │ │ └── webhook-workflows.ts │ │ │ └── workflows │ │ │ ├── autofix-workflow.test.ts │ │ │ ├── create-workflow.test.ts │ │ │ ├── delete-workflow.test.ts │ │ │ ├── get-workflow-details.test.ts │ │ │ ├── get-workflow-minimal.test.ts │ │ │ ├── get-workflow-structure.test.ts │ │ │ ├── get-workflow.test.ts │ │ │ ├── list-workflows.test.ts │ │ │ ├── smart-parameters.test.ts │ │ │ ├── update-partial-workflow.test.ts │ │ │ ├── update-workflow.test.ts │ │ │ └── validate-workflow.test.ts │ │ ├── security │ │ │ ├── command-injection-prevention.test.ts │ │ │ └── rate-limiting.test.ts │ │ ├── session │ │ │ └── test-onSessionCreated-event.ts │ │ ├── session-lifecycle-retry.test.ts │ │ ├── session-persistence.test.ts │ │ ├── setup │ │ │ ├── integration-setup.ts │ │ │ └── msw-test-server.ts │ │ ├── telemetry │ │ │ ├── docker-user-id-stability.test.ts │ │ │ └── mcp-telemetry.test.ts │ │ ├── templates │ │ │ └── metadata-operations.test.ts │ │ └── workflow-creation-node-type-format.test.ts │ ├── logger.test.ts │ ├── MOCKING_STRATEGY.md │ ├── mocks │ │ ├── n8n-api │ │ │ ├── data │ │ │ │ ├── credentials.ts │ │ │ │ ├── executions.ts │ │ │ │ └── workflows.ts │ │ │ ├── handlers.ts │ │ │ └── index.ts │ │ └── README.md │ ├── node-storage-export.json │ ├── setup │ │ ├── global-setup.ts │ │ ├── msw-setup.ts │ │ ├── TEST_ENV_DOCUMENTATION.md │ │ └── test-env.ts │ ├── test-database-extraction.js │ ├── test-direct-extraction.js │ ├── test-enhanced-documentation.js │ ├── test-enhanced-integration.js │ ├── test-mcp-extraction.js │ ├── test-mcp-server-extraction.js │ ├── test-mcp-tools-integration.js │ ├── test-node-documentation-service.js │ ├── test-node-list.js │ ├── test-package-info.js │ ├── test-parsing-operations.js │ ├── test-slack-node-complete.js │ ├── test-small-rebuild.js │ ├── test-sqlite-search.js │ ├── test-storage-system.js │ ├── unit │ │ ├── __mocks__ │ │ │ ├── n8n-nodes-base.test.ts │ │ │ ├── n8n-nodes-base.ts │ │ │ └── README.md │ │ ├── database │ │ │ ├── __mocks__ │ │ │ │ └── better-sqlite3.ts │ │ │ ├── database-adapter-unit.test.ts │ │ │ ├── node-repository-core.test.ts │ │ │ ├── node-repository-operations.test.ts │ │ │ ├── node-repository-outputs.test.ts │ │ │ ├── README.md │ │ │ └── template-repository-core.test.ts │ │ ├── docker │ │ │ ├── config-security.test.ts │ │ │ ├── edge-cases.test.ts │ │ │ ├── parse-config.test.ts │ │ │ └── serve-command.test.ts │ │ ├── errors │ │ │ └── validation-service-error.test.ts │ │ ├── examples │ │ │ └── using-n8n-nodes-base-mock.test.ts │ │ ├── flexible-instance-security-advanced.test.ts │ │ ├── flexible-instance-security.test.ts │ │ ├── http-server │ │ │ └── multi-tenant-support.test.ts │ │ ├── http-server-n8n-mode.test.ts │ │ ├── http-server-n8n-reinit.test.ts │ │ ├── http-server-session-management.test.ts │ │ ├── loaders │ │ │ └── node-loader.test.ts │ │ ├── mappers │ │ │ └── docs-mapper.test.ts │ │ ├── mcp │ │ │ ├── get-node-essentials-examples.test.ts │ │ │ ├── handlers-n8n-manager-simple.test.ts │ │ │ ├── handlers-n8n-manager.test.ts │ │ │ ├── handlers-workflow-diff.test.ts │ │ │ ├── lru-cache-behavior.test.ts │ │ │ ├── multi-tenant-tool-listing.test.ts.disabled │ │ │ ├── parameter-validation.test.ts │ │ │ ├── search-nodes-examples.test.ts │ │ │ ├── tools-documentation.test.ts │ │ │ └── tools.test.ts │ │ ├── monitoring │ │ │ └── cache-metrics.test.ts │ │ ├── MULTI_TENANT_TEST_COVERAGE.md │ │ ├── multi-tenant-integration.test.ts │ │ ├── parsers │ │ │ ├── node-parser-outputs.test.ts │ │ │ ├── node-parser.test.ts │ │ │ ├── property-extractor.test.ts │ │ │ └── simple-parser.test.ts │ │ ├── scripts │ │ │ └── fetch-templates-extraction.test.ts │ │ ├── services │ │ │ ├── ai-node-validator.test.ts │ │ │ ├── ai-tool-validators.test.ts │ │ │ ├── confidence-scorer.test.ts │ │ │ ├── config-validator-basic.test.ts │ │ │ ├── config-validator-edge-cases.test.ts │ │ │ ├── config-validator-node-specific.test.ts │ │ │ ├── config-validator-security.test.ts │ │ │ ├── debug-validator.test.ts │ │ │ ├── enhanced-config-validator-integration.test.ts │ │ │ ├── enhanced-config-validator-operations.test.ts │ │ │ ├── enhanced-config-validator.test.ts │ │ │ ├── example-generator.test.ts │ │ │ ├── execution-processor.test.ts │ │ │ ├── expression-format-validator.test.ts │ │ │ ├── expression-validator-edge-cases.test.ts │ │ │ ├── expression-validator.test.ts │ │ │ ├── fixed-collection-validation.test.ts │ │ │ ├── loop-output-edge-cases.test.ts │ │ │ ├── n8n-api-client.test.ts │ │ │ ├── n8n-validation.test.ts │ │ │ ├── node-similarity-service.test.ts │ │ │ ├── node-specific-validators.test.ts │ │ │ ├── operation-similarity-service-comprehensive.test.ts │ │ │ ├── operation-similarity-service.test.ts │ │ │ ├── property-dependencies.test.ts │ │ │ ├── property-filter-edge-cases.test.ts │ │ │ ├── property-filter.test.ts │ │ │ ├── resource-similarity-service-comprehensive.test.ts │ │ │ ├── resource-similarity-service.test.ts │ │ │ ├── task-templates.test.ts │ │ │ ├── template-service.test.ts │ │ │ ├── universal-expression-validator.test.ts │ │ │ ├── validation-fixes.test.ts │ │ │ ├── workflow-auto-fixer.test.ts │ │ │ ├── workflow-diff-engine.test.ts │ │ │ ├── workflow-fixed-collection-validation.test.ts │ │ │ ├── workflow-validator-comprehensive.test.ts │ │ │ ├── workflow-validator-edge-cases.test.ts │ │ │ ├── workflow-validator-error-outputs.test.ts │ │ │ ├── workflow-validator-expression-format.test.ts │ │ │ ├── workflow-validator-loops-simple.test.ts │ │ │ ├── workflow-validator-loops.test.ts │ │ │ ├── workflow-validator-mocks.test.ts │ │ │ ├── workflow-validator-performance.test.ts │ │ │ ├── workflow-validator-with-mocks.test.ts │ │ │ └── workflow-validator.test.ts │ │ ├── session-lifecycle-events.test.ts │ │ ├── session-management-api.test.ts │ │ ├── session-restoration-retry.test.ts │ │ ├── session-restoration.test.ts │ │ ├── telemetry │ │ │ ├── batch-processor.test.ts │ │ │ ├── config-manager.test.ts │ │ │ ├── event-tracker.test.ts │ │ │ ├── event-validator.test.ts │ │ │ ├── rate-limiter.test.ts │ │ │ ├── telemetry-error.test.ts │ │ │ ├── telemetry-manager.test.ts │ │ │ ├── v2.18.3-fixes-verification.test.ts │ │ │ └── workflow-sanitizer.test.ts │ │ ├── templates │ │ │ ├── batch-processor.test.ts │ │ │ ├── metadata-generator.test.ts │ │ │ ├── template-repository-metadata.test.ts │ │ │ └── template-repository-security.test.ts │ │ ├── test-env-example.test.ts │ │ ├── test-infrastructure.test.ts │ │ ├── types │ │ │ ├── instance-context-coverage.test.ts │ │ │ └── instance-context-multi-tenant.test.ts │ │ ├── utils │ │ │ ├── auth-timing-safe.test.ts │ │ │ ├── cache-utils.test.ts │ │ │ ├── console-manager.test.ts │ │ │ ├── database-utils.test.ts │ │ │ ├── fixed-collection-validator.test.ts │ │ │ ├── n8n-errors.test.ts │ │ │ ├── node-type-normalizer.test.ts │ │ │ ├── node-type-utils.test.ts │ │ │ ├── node-utils.test.ts │ │ │ ├── simple-cache-memory-leak-fix.test.ts │ │ │ ├── ssrf-protection.test.ts │ │ │ └── template-node-resolver.test.ts │ │ └── validation-fixes.test.ts │ └── utils │ ├── assertions.ts │ ├── builders │ │ └── workflow.builder.ts │ ├── data-generators.ts │ ├── database-utils.ts │ ├── README.md │ └── test-helpers.ts ├── thumbnail.png ├── tsconfig.build.json ├── tsconfig.json ├── types │ ├── mcp.d.ts │ └── test-env.d.ts ├── verify-telemetry-fix.js ├── versioned-nodes.md ├── vitest.config.benchmark.ts ├── vitest.config.integration.ts └── vitest.config.ts ``` # Files -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- ``` ``` -------------------------------------------------------------------------------- /tests/__snapshots__/.gitkeep: -------------------------------------------------------------------------------- ``` ``` -------------------------------------------------------------------------------- /tests/data/.gitkeep: -------------------------------------------------------------------------------- ``` ``` -------------------------------------------------------------------------------- /tests/fixtures/.gitkeep: -------------------------------------------------------------------------------- ``` ``` -------------------------------------------------------------------------------- /.env.docker: -------------------------------------------------------------------------------- ``` # .env.docker # Docker-specific environment template # Copy to .env and fill in values # Required for HTTP mode AUTH_TOKEN= # Server configuration PORT=3000 HTTP_PORT=80 HTTPS_PORT=443 # Application settings NODE_ENV=production LOG_LEVEL=info MCP_MODE=http # Database NODE_DB_PATH=/app/data/nodes.db REBUILD_ON_START=false # Optional nginx mode USE_NGINX=false # Optional n8n API configuration (enables 16 additional management tools) # N8N_API_URL=https://your-n8n-instance.com # N8N_API_KEY=your-api-key-here # N8N_API_TIMEOUT=30000 # N8N_API_MAX_RETRIES=3 ``` -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- ``` # Source files (TypeScript) src/ *.ts !dist/**/*.d.ts # Development files .github/ scripts/ tests/ docs/ *.test.js *.spec.js # Build files tsconfig.json jest.config.js nodemon.json renovate.json # Docker files (not needed for npm) Dockerfile* docker-compose*.yml docker/ .dockerignore # Environment and config files .env .env.* !.env.example # IDE and OS files .vscode/ .idea/ *.swp .DS_Store # Logs and temp files *.log npm-debug.log* yarn-debug.log* yarn-error.log* *.pid *.seed *.pid.lock # Coverage and test reports coverage/ .nyc_output/ # Git files .git/ .gitignore # Documentation source files *.md !README.md !LICENSE # Package files we don't want to publish package-lock.json yarn.lock pnpm-lock.yaml # Backup files *.backup *.bak # Keep only necessary runtime files !dist/ !data/nodes.db !package.json !package.runtime.json ``` -------------------------------------------------------------------------------- /.env.n8n.example: -------------------------------------------------------------------------------- ``` # n8n-mcp Docker Environment Configuration # Copy this file to .env and customize for your deployment # === n8n Configuration === # n8n basic auth (change these in production!) N8N_BASIC_AUTH_ACTIVE=true N8N_BASIC_AUTH_USER=admin N8N_BASIC_AUTH_PASSWORD=changeme # n8n host configuration N8N_HOST=localhost N8N_PORT=5678 N8N_PROTOCOL=http N8N_WEBHOOK_URL=http://localhost:5678/ # n8n encryption key (generate with: openssl rand -hex 32) N8N_ENCRYPTION_KEY= # === n8n-mcp Configuration === # MCP server port MCP_PORT=3000 # MCP authentication token (generate with: openssl rand -hex 32) MCP_AUTH_TOKEN= # n8n API key for MCP to access n8n # Get this from n8n UI: Settings > n8n API > Create API Key N8N_API_KEY= # Logging level (debug, info, warn, error) LOG_LEVEL=info # === GitHub Container Registry (for CI/CD) === # Only needed if building custom images GITHUB_REPOSITORY=czlonkowski/n8n-mcp VERSION=latest ``` -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- ``` # .dockerignore node_modules npm-debug.log .git .gitignore .env .env.local # Exclude all .env.* files except .env.example .env.* !.env.example # Keep nodes.db but exclude other database files data/*.db data/*.db-* !data/nodes.db dist .DS_Store *.log coverage .nyc_output .vscode .idea *.swp *.swo *~ docker-compose.override.yml .github docs tests jest.config.js .eslintrc.js *.md !README.md !LICENSE # Exclude n8n-docs if present ../n8n-docs n8n-docs # Exclude extracted nodes extracted-nodes/ # Exclude temp directory temp/ tmp/ # Exclude any backup or temporary files *.bak *.tmp *.temp # Exclude build artifacts build/ out/ # Exclude local development files .eslintcache .stylelintcache # Exclude any large test data test-data/ # Exclude Docker files during build Dockerfile* docker-compose*.yml .dockerignore # Exclude development scripts scripts/test-*.sh scripts/deploy-*.sh # Exclude TypeScript cache .tscache tsconfig.tsbuildinfo # Exclude package manager caches .npm .pnpm-store .yarn # Exclude git hooks .husky # Exclude renovate config renovate.json # Exclude any local notes or TODO files TODO* NOTES* *.todo ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` # Dependencies node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* # Environment variables .env .env.local .env.development.local .env.test.local .env.production.local .env*.local # Build output dist/ build/ out/ .next/ .nuxt/ .cache/ .parcel-cache/ # IDE and editor files .vscode/ .idea/ *.swp *.swo *~ .DS_Store Thumbs.db # Logs logs/ *.log # Testing coverage/ .nyc_output/ test-results/ test-reports/ test-summary.md test-metadata.json benchmark-results.json benchmark-results*.json benchmark-summary.json coverage-report.json benchmark-comparison.md benchmark-comparison.json benchmark-current.json benchmark-baseline.json tests/data/*.db tests/fixtures/*.tmp tests/test-results/ .test-dbs/ junit.xml *.test.db test-*.db .vitest/ # TypeScript *.tsbuildinfo .tsc-cache/ # Package manager files .npm/ .yarn/ .pnp.* .yarn-integrity # Docker docker-compose.override.yml # Miscellaneous .eslintcache .stylelintcache *.pid *.seed *.pid.lock .grunt/ .lock-wscript .node_repl_history .npmrc .yarnrc # Temporary files temp/ tmp/ # Batch processing error files (may contain API tokens from templates) docs/batch_*.jsonl **/batch_*_error.jsonl # Local documentation and analysis files docs/local/ # Database files # Database files - nodes.db is now tracked directly # data/*.db data/*.db-journal data/*.db.bak data/*.db.backup !data/.gitkeep !data/nodes.db # Claude Desktop configs (personal) claude_desktop_config.json claude_desktop_config_*.json !claude_desktop_config.example.json # Personal wrapper scripts mcp-server-v20.sh rebuild-v20.sh !mcp-server-v20.example.sh # n8n-docs repo (cloned locally) ../n8n-docs/ n8n-docs/ # npm publish temporary directory npm-publish-temp/ # Test files and logs test-npx/ mcp-server-*.log server.log server-fixed.log mcp-debug.log # Temporary wrapper scripts n8n-mcp-wrapper.sh # Package tarballs *.tgz # MCP configuration files .mcp.json # Telemetry configuration (user-specific) ~/.n8n-mcp/ ``` -------------------------------------------------------------------------------- /.env.test.example: -------------------------------------------------------------------------------- ``` # Example Test Environment Configuration # Copy this file to .env.test and adjust values as needed # For sensitive values, create .env.test.local (not committed to git) # === Test Mode Configuration === NODE_ENV=test MCP_MODE=test TEST_ENVIRONMENT=true # === Database Configuration === # Use :memory: for in-memory SQLite or provide a file path NODE_DB_PATH=:memory: REBUILD_ON_START=false TEST_SEED_DATABASE=true TEST_SEED_TEMPLATES=true # === API Configuration === # Mock API endpoints for testing N8N_API_URL=http://localhost:3001/mock-api N8N_API_KEY=your-test-api-key N8N_WEBHOOK_BASE_URL=http://localhost:3001/webhook N8N_WEBHOOK_TEST_URL=http://localhost:3001/webhook-test # === Test Server Configuration === PORT=3001 HOST=127.0.0.1 CORS_ORIGIN=http://localhost:3000,http://localhost:5678 # === Authentication === AUTH_TOKEN=test-auth-token MCP_AUTH_TOKEN=test-mcp-auth-token # === Logging Configuration === LOG_LEVEL=error DEBUG=false TEST_LOG_VERBOSE=false ERROR_SHOW_STACK=true ERROR_SHOW_DETAILS=true # === Test Execution Configuration === TEST_TIMEOUT_UNIT=5000 TEST_TIMEOUT_INTEGRATION=15000 TEST_TIMEOUT_E2E=30000 TEST_TIMEOUT_GLOBAL=60000 TEST_RETRY_ATTEMPTS=2 TEST_RETRY_DELAY=1000 TEST_PARALLEL=true TEST_MAX_WORKERS=4 # === Feature Flags === FEATURE_TEST_COVERAGE=true FEATURE_TEST_SCREENSHOTS=false FEATURE_TEST_VIDEOS=false FEATURE_TEST_TRACE=false FEATURE_MOCK_EXTERNAL_APIS=true FEATURE_USE_TEST_CONTAINERS=false # === Mock Service Configuration === MSW_ENABLED=true MSW_API_DELAY=0 REDIS_MOCK_ENABLED=true REDIS_MOCK_PORT=6380 ELASTICSEARCH_MOCK_ENABLED=false ELASTICSEARCH_MOCK_PORT=9201 # === Test Data Paths === TEST_FIXTURES_PATH=./tests/fixtures TEST_DATA_PATH=./tests/data TEST_SNAPSHOTS_PATH=./tests/__snapshots__ # === Performance Testing === PERF_THRESHOLD_API_RESPONSE=100 PERF_THRESHOLD_DB_QUERY=50 PERF_THRESHOLD_NODE_PARSE=200 # === Rate Limiting === RATE_LIMIT_MAX=0 RATE_LIMIT_WINDOW=0 # === Cache Configuration === CACHE_TTL=0 CACHE_ENABLED=false # === Cleanup Configuration === TEST_CLEANUP_ENABLED=true TEST_CLEANUP_ON_FAILURE=false # === Network Configuration === NETWORK_TIMEOUT=5000 NETWORK_RETRY_COUNT=0 # === Memory Limits === TEST_MEMORY_LIMIT=512 # === Code Coverage === COVERAGE_DIR=./coverage COVERAGE_REPORTER=lcov,html,text-summary ``` -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- ``` # Test Environment Configuration for n8n-mcp # This file contains test-specific environment variables # DO NOT commit sensitive values - use .env.test.local for secrets # === Test Mode Configuration === NODE_ENV=test MCP_MODE=test TEST_ENVIRONMENT=true # === Database Configuration === # Use in-memory database for tests by default NODE_DB_PATH=:memory: # Uncomment to use a persistent test database # NODE_DB_PATH=./tests/fixtures/test-nodes.db REBUILD_ON_START=false # === API Configuration for Mocking === # Mock API endpoints N8N_API_URL=http://localhost:3001/mock-api N8N_API_KEY=test-api-key-12345 N8N_WEBHOOK_BASE_URL=http://localhost:3001/webhook N8N_WEBHOOK_TEST_URL=http://localhost:3001/webhook-test # === Test Server Configuration === PORT=3001 HOST=127.0.0.1 CORS_ORIGIN=http://localhost:3000,http://localhost:5678 # === Authentication === AUTH_TOKEN=test-auth-token MCP_AUTH_TOKEN=test-mcp-auth-token # === Logging Configuration === # Set to 'debug' for verbose test output LOG_LEVEL=error # Enable debug logging for specific tests DEBUG=false # Log test execution details TEST_LOG_VERBOSE=false # === Test Execution Configuration === # Test timeouts (in milliseconds) TEST_TIMEOUT_UNIT=5000 TEST_TIMEOUT_INTEGRATION=15000 TEST_TIMEOUT_E2E=30000 TEST_TIMEOUT_GLOBAL=60000 # Test retry configuration TEST_RETRY_ATTEMPTS=2 TEST_RETRY_DELAY=1000 # Parallel execution TEST_PARALLEL=true TEST_MAX_WORKERS=4 # === Feature Flags === # Enable/disable specific test features FEATURE_TEST_COVERAGE=true FEATURE_TEST_SCREENSHOTS=false FEATURE_TEST_VIDEOS=false FEATURE_TEST_TRACE=false FEATURE_MOCK_EXTERNAL_APIS=true FEATURE_USE_TEST_CONTAINERS=false # === Mock Service Configuration === # MSW (Mock Service Worker) configuration MSW_ENABLED=true MSW_API_DELAY=0 # Test data paths TEST_FIXTURES_PATH=./tests/fixtures TEST_DATA_PATH=./tests/data TEST_SNAPSHOTS_PATH=./tests/__snapshots__ # === Performance Testing === # Performance thresholds (in milliseconds) PERF_THRESHOLD_API_RESPONSE=100 PERF_THRESHOLD_DB_QUERY=50 PERF_THRESHOLD_NODE_PARSE=200 # === External Service Mocks === # Redis mock (if needed) REDIS_MOCK_ENABLED=true REDIS_MOCK_PORT=6380 # Elasticsearch mock (if needed) ELASTICSEARCH_MOCK_ENABLED=false ELASTICSEARCH_MOCK_PORT=9201 # === Rate Limiting === # Disable rate limiting in tests RATE_LIMIT_MAX=0 RATE_LIMIT_WINDOW=0 # === Cache Configuration === # Disable caching in tests for predictable results CACHE_TTL=0 CACHE_ENABLED=false # === Error Handling === # Show full error stack traces in tests ERROR_SHOW_STACK=true ERROR_SHOW_DETAILS=true # === Cleanup Configuration === # Automatically clean up test data after each test TEST_CLEANUP_ENABLED=true TEST_CLEANUP_ON_FAILURE=false # === Database Seeding === # Seed test database with sample data TEST_SEED_DATABASE=true TEST_SEED_TEMPLATES=true # === Network Configuration === # Network timeouts for external requests NETWORK_TIMEOUT=5000 NETWORK_RETRY_COUNT=0 # === Memory Limits === # Set memory limits for tests (in MB) TEST_MEMORY_LIMIT=512 # === Code Coverage === # Coverage output directory COVERAGE_DIR=./coverage COVERAGE_REPORTER=lcov,html,text-summary ``` -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- ``` # n8n Documentation MCP Server Configuration # ==================== # COMMON CONFIGURATION # ==================== # Database Configuration # For local development: ./data/nodes.db # For Docker: /app/data/nodes.db # Custom paths supported in v2.7.16+ (must end with .db) NODE_DB_PATH=./data/nodes.db # Logging Level (debug, info, warn, error) MCP_LOG_LEVEL=info # Node Environment (development, production) NODE_ENV=development # Rebuild database on startup (true/false) REBUILD_ON_START=false # ========================= # LOCAL MODE CONFIGURATION # ========================= # Used when running: npm run start:v2 or npm run dev:v2 # Local MCP Server Configuration MCP_SERVER_PORT=3000 MCP_SERVER_HOST=localhost # MCP_AUTH_TOKEN=optional-for-local-development # ========================= # SIMPLE HTTP MODE # ========================= # Used for private single-user deployments # Server mode: stdio (local) or http (remote) MCP_MODE=stdio # Use fixed HTTP implementation (recommended for stability) # Set to true to bypass StreamableHTTPServerTransport issues USE_FIXED_HTTP=true # HTTP Server Configuration (only used when MCP_MODE=http) PORT=3000 HOST=0.0.0.0 # Base URL Configuration (optional) # Set this when running behind a proxy or when the server is accessed via a different URL # than what it binds to. If not set, URLs will be auto-detected from proxy headers (if TRUST_PROXY is set) # or constructed from HOST and PORT. # Examples: # BASE_URL=https://n8n-mcp.example.com # BASE_URL=https://your-domain.com:8443 # PUBLIC_URL=https://n8n-mcp.mydomain.com (alternative to BASE_URL) # Authentication token for HTTP mode (REQUIRED) # Generate with: openssl rand -base64 32 AUTH_TOKEN=your-secure-token-here # CORS origin for HTTP mode (optional) # Default: * (allow all origins) # For production, set to your specific domain # CORS_ORIGIN=https://your-client-domain.com # Trust proxy configuration for correct IP logging (0=disabled, 1=trust first proxy) # Set to 1 when running behind a reverse proxy (Nginx, Traefik, etc.) # Set to the number of proxy hops if behind multiple proxies # Default: 0 (disabled) # TRUST_PROXY=0 # ========================= # SECURITY CONFIGURATION # ========================= # Rate Limiting Configuration # Protects authentication endpoint from brute force attacks # Window: Time period in milliseconds (default: 900000 = 15 minutes) # Max: Maximum authentication attempts per IP within window (default: 20) # AUTH_RATE_LIMIT_WINDOW=900000 # AUTH_RATE_LIMIT_MAX=20 # SSRF Protection Mode # Prevents webhooks from accessing internal networks and cloud metadata # # Modes: # - strict (default): Block localhost + private IPs + cloud metadata # Use for: Production deployments, cloud environments # Security: Maximum # # - moderate: Allow localhost, block private IPs + cloud metadata # Use for: Local development with local n8n instance # Security: Good balance # Example: n8n running on http://localhost:5678 or http://host.docker.internal:5678 # # - permissive: Allow localhost + private IPs, block cloud metadata # Use for: Internal network testing, private cloud (NOT for production) # Security: Minimal - use with caution # # Default: strict # WEBHOOK_SECURITY_MODE=strict # # For local development with local n8n: # WEBHOOK_SECURITY_MODE=moderate # ========================= # MULTI-TENANT CONFIGURATION # ========================= # Enable multi-tenant mode for dynamic instance support # When enabled, n8n API tools will be available for all sessions, # and instance configuration will be determined from HTTP headers # Default: false (single-tenant mode using environment variables) ENABLE_MULTI_TENANT=false # Session isolation strategy for multi-tenant mode # - "instance": Create separate sessions per instance ID (recommended) # - "shared": Share sessions but switch contexts (advanced) # Default: instance # MULTI_TENANT_SESSION_STRATEGY=instance # ========================= # N8N API CONFIGURATION # ========================= # Optional: Enable n8n management tools by providing API credentials # These tools allow creating, updating, and executing workflows # n8n instance API URL (without /api/v1 suffix) # Example: https://your-n8n-instance.com # N8N_API_URL= # n8n API Key (get from Settings > API in your n8n instance) # N8N_API_KEY= # n8n API request timeout in milliseconds (default: 30000) # N8N_API_TIMEOUT=30000 # Maximum number of API request retries (default: 3) # N8N_API_MAX_RETRIES=3 # ========================= # CACHE CONFIGURATION # ========================= # Optional: Configure instance cache settings for flexible instance support # Maximum number of cached instances (default: 100, min: 1, max: 10000) # INSTANCE_CACHE_MAX=100 # Cache TTL in minutes (default: 30, min: 1, max: 1440/24 hours) # INSTANCE_CACHE_TTL_MINUTES=30 # ========================= # OPENAI API CONFIGURATION # ========================= # Optional: Enable AI-powered template metadata generation # Provides structured metadata for improved template discovery # OpenAI API Key (get from https://platform.openai.com/api-keys) # OPENAI_API_KEY= # OpenAI Model for metadata generation (default: gpt-4o-mini) # OPENAI_MODEL=gpt-4o-mini # Batch size for metadata generation (default: 100) # Templates are processed in batches using OpenAI's Batch API for 50% cost savings # OPENAI_BATCH_SIZE=100 # Enable metadata generation during template fetch (default: false) # Set to true to automatically generate metadata when running fetch:templates # METADATA_GENERATION_ENABLED=false # ======================================== # INTEGRATION TESTING CONFIGURATION # ======================================== # Configuration for integration tests that call real n8n instance API # n8n API Configuration for Integration Tests # For local development: Use your local n8n instance # For CI: These will be provided by GitHub secrets # N8N_API_URL=http://localhost:5678 # N8N_API_KEY= # Pre-activated Webhook Workflows for Testing # These workflows must be created manually in n8n and activated # because n8n API doesn't support workflow activation. # # Setup Instructions: # 1. Create 4 workflows in n8n UI (one for each HTTP method) # 2. Each workflow should have a single Webhook node # 3. Configure webhook paths: mcp-test-get, mcp-test-post, mcp-test-put, mcp-test-delete # 4. ACTIVATE each workflow in n8n UI # 5. Copy the workflow IDs here # # N8N_TEST_WEBHOOK_GET_ID= # Workflow ID for GET method webhook # N8N_TEST_WEBHOOK_POST_ID= # Workflow ID for POST method webhook # N8N_TEST_WEBHOOK_PUT_ID= # Workflow ID for PUT method webhook # N8N_TEST_WEBHOOK_DELETE_ID= # Workflow ID for DELETE method webhook # Test Configuration N8N_TEST_CLEANUP_ENABLED=true # Enable automatic cleanup of test workflows N8N_TEST_TAG=mcp-integration-test # Tag applied to all test workflows N8N_TEST_NAME_PREFIX=[MCP-TEST] # Name prefix for test workflows ``` -------------------------------------------------------------------------------- /tests/integration/mcp-protocol/README.md: -------------------------------------------------------------------------------- ```markdown # MCP Protocol Integration Tests This directory contains comprehensive integration tests for the Model Context Protocol (MCP) implementation in n8n-mcp. ## Test Structure ### Core Tests - **basic-connection.test.ts** - Tests basic MCP server functionality and tool execution - **protocol-compliance.test.ts** - Tests JSON-RPC 2.0 compliance and protocol specifications - **tool-invocation.test.ts** - Tests all MCP tool categories and their invocation - **session-management.test.ts** - Tests session lifecycle, multiple sessions, and recovery - **error-handling.test.ts** - Tests error handling, edge cases, and invalid inputs - **performance.test.ts** - Performance benchmarks and stress tests ### Helper Files - **test-helpers.ts** - TestableN8NMCPServer wrapper for testing with custom transports ## Running Tests ```bash # Run all MCP protocol tests npm test -- tests/integration/mcp-protocol/ # Run specific test file npm test -- tests/integration/mcp-protocol/basic-connection.test.ts # Run with coverage npm test -- tests/integration/mcp-protocol/ --coverage ``` ## Test Coverage These tests ensure: - ✅ JSON-RPC 2.0 protocol compliance - ✅ Proper request/response handling - ✅ All tool categories are tested - ✅ Error handling and edge cases - ✅ Session management and lifecycle - ✅ Performance and scalability ## Known Issues 1. The InMemoryTransport from MCP SDK has some limitations with connection lifecycle 2. Tests use the actual database, so they require `data/nodes.db` to exist 3. Some tests are currently skipped due to transport issues (being worked on) ## Future Improvements 1. Mock the database for true unit testing 2. Add WebSocket transport tests 3. Add authentication/authorization tests 4. Add rate limiting tests 5. Add more performance benchmarks ``` -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- ```markdown # Docker Usage Guide for n8n-mcp ## Running in HTTP Mode The n8n-mcp Docker container can be run in HTTP mode using several methods: ### Method 1: Using Environment Variables (Recommended) ```bash docker run -d -p 3000:3000 \ --name n8n-mcp-server \ -e MCP_MODE=http \ -e AUTH_TOKEN=your-secure-token-here \ ghcr.io/czlonkowski/n8n-mcp:latest ``` ### Method 2: Using docker-compose ```bash # Create a .env file cat > .env << EOF MCP_MODE=http AUTH_TOKEN=your-secure-token-here PORT=3000 EOF # Run with docker-compose docker-compose up -d ``` ### Method 3: Using a Configuration File Create a `config.json` file: ```json { "MCP_MODE": "http", "AUTH_TOKEN": "your-secure-token-here", "PORT": "3000", "LOG_LEVEL": "info" } ``` Run with the config file: ```bash docker run -d -p 3000:3000 \ --name n8n-mcp-server \ -v $(pwd)/config.json:/app/config.json:ro \ ghcr.io/czlonkowski/n8n-mcp:latest ``` ### Method 4: Using the n8n-mcp serve Command ```bash docker run -d -p 3000:3000 \ --name n8n-mcp-server \ -e AUTH_TOKEN=your-secure-token-here \ ghcr.io/czlonkowski/n8n-mcp:latest \ n8n-mcp serve ``` ## Important Notes 1. **AUTH_TOKEN is required** for HTTP mode. Generate a secure token: ```bash openssl rand -base64 32 ``` 2. **Environment variables take precedence** over config file values 3. **Default mode is stdio** if MCP_MODE is not specified 4. **Health check endpoint** is available at `http://localhost:3000/health` ## Troubleshooting ### Container exits immediately - Check logs: `docker logs n8n-mcp-server` - Ensure AUTH_TOKEN is set for HTTP mode ### "n8n-mcp: not found" error - This has been fixed in the latest version - Use the full command: `node /app/dist/mcp/index.js` as a workaround ### Config file not working - Ensure the file is valid JSON - Mount as read-only: `-v $(pwd)/config.json:/app/config.json:ro` - Check that the config parser is present: `docker exec n8n-mcp-server ls -la /app/docker/` ``` -------------------------------------------------------------------------------- /tests/unit/database/README.md: -------------------------------------------------------------------------------- ```markdown # Database Layer Unit Tests This directory contains comprehensive unit tests for the database layer components of n8n-mcp. ## Test Coverage ### node-repository.ts - 100% Coverage ✅ - `saveNode` method with JSON serialization - `getNode` method with JSON deserialization - `getAITools` method - `safeJsonParse` private method - Edge cases: large JSON, boolean conversion, invalid JSON handling ### template-repository.ts - 80.31% Coverage ✅ - FTS5 initialization and fallback - `saveTemplate` with sanitization - `getTemplate` and `getTemplatesByNodes` - `searchTemplates` with FTS5 and LIKE fallback - `getTemplatesForTask` with task mapping - Template statistics and maintenance operations - Uncovered: Some error paths in FTS5 operations ### database-adapter.ts - Tested via Mocks - Interface compliance tests - PreparedStatement implementation - Transaction support - FTS5 detection logic - Error handling patterns ## Test Strategy The tests use a mock-based approach to: 1. Isolate database operations from actual database dependencies 2. Test business logic without requiring real SQLite/sql.js 3. Ensure consistent test execution across environments 4. Focus on behavior rather than implementation details ## Key Test Files - `node-repository-core.test.ts` - Core NodeRepository functionality - `template-repository-core.test.ts` - Core TemplateRepository functionality - `database-adapter-unit.test.ts` - DatabaseAdapter interface and patterns ## Running Tests ```bash # Run all database tests npm test -- tests/unit/database/ # Run with coverage npm run test:coverage -- tests/unit/database/ # Run specific test file npm test -- tests/unit/database/node-repository-core.test.ts ``` ## Mock Infrastructure The tests use custom mock implementations: - `MockDatabaseAdapter` - Simulates database operations - `MockPreparedStatement` - Simulates SQL statement execution - Mock logger and template sanitizer for external dependencies This approach ensures tests are fast, reliable, and maintainable. ``` -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- ```markdown # n8n-MCP Documentation Welcome to the n8n-MCP documentation. This directory contains comprehensive guides for installation, configuration, and troubleshooting. ## 📚 Documentation Index ### Getting Started - **[Installation Guide](./INSTALLATION.md)** - Comprehensive installation guide covering all methods - **[Claude Desktop Setup](./README_CLAUDE_SETUP.md)** - Step-by-step guide for Claude Desktop configuration - **[Quick Start Tutorial](../README.md)** - Basic overview and quick start instructions ### Deployment - **[HTTP Deployment Guide](./HTTP_DEPLOYMENT.md)** - Deploy n8n-MCP as an HTTP server for remote access - **[Docker Deployment](./DOCKER_README.md)** - Complete Docker deployment and configuration guide - **[Release Guide](./RELEASE_GUIDE.md)** - How to create releases and manage Docker tags ### Reference - **[Troubleshooting Guide](./TROUBLESHOOTING.md)** - Solutions for common issues and errors - **[HTTP Server Fix Documentation](./HTTP_SERVER_FINAL_FIX.md)** - Technical details of v2.3.2 HTTP server fixes - **[Docker Optimization Guide](./DOCKER_OPTIMIZATION_GUIDE.md)** - Reference for optimized Docker builds (~150MB) - **[Changelog](./CHANGELOG.md)** - Version history and release notes ## 🚀 Quick Links ### For Users - [Install n8n-MCP](./INSTALLATION.md) - [Configure Claude Desktop](./README_CLAUDE_SETUP.md) - [Deploy with Docker](./DOCKER_README.md) - [Troubleshoot Issues](./TROUBLESHOOTING.md) ### For Developers - [HTTP Server Architecture](./HTTP_SERVER_FINAL_FIX.md) - [Docker Build Optimization](./DOCKER_OPTIMIZATION_GUIDE.md) - [Release Process](./RELEASE_GUIDE.md) ## 📋 Environment Variables Key configuration options: | Variable | Description | Default | |----------|-------------|---------| | `MCP_MODE` | Server mode: `stdio` or `http` | `stdio` | | `USE_FIXED_HTTP` | Use fixed HTTP implementation (v2.3.2+) | `true` | | `AUTH_TOKEN` | Authentication token for HTTP mode | Required | | `PORT` | HTTP server port | `3000` | | `LOG_LEVEL` | Logging verbosity | `info` | See [Installation Guide](./INSTALLATION.md#environment-configuration) for complete list. ## 🆘 Getting Help 1. Check the [Troubleshooting Guide](./TROUBLESHOOTING.md) 2. Review [HTTP Server Fix Documentation](./HTTP_SERVER_FINAL_FIX.md) for v2.3.2 issues 3. Open an issue on [GitHub](https://github.com/czlonkowski/n8n-mcp/issues) ## 📝 License This project uses the Sustainable Use License. See [LICENSE](../LICENSE) for details. ``` -------------------------------------------------------------------------------- /src/templates/README.md: -------------------------------------------------------------------------------- ```markdown # n8n Templates Integration This module provides integration with n8n.io's workflow templates, allowing AI agents to discover and use proven workflow patterns. ## Features - **API Integration**: Connects to n8n.io's official template API - **Fresh Templates**: Only includes templates updated within the last 6 months - **Manual Fetch**: Templates are fetched separately from the main node database - **Full Workflow JSON**: Complete workflow definitions ready for import - **Smart Search**: Find templates by nodes, keywords, or task categories ## Usage ### Fetching Templates ```bash npm run fetch:templates ``` This command will: 1. Connect to n8n.io API 2. Fetch all templates from the last 6 months 3. Download complete workflow JSON for each template 4. Store in local SQLite database 5. Display progress and statistics ### Testing ```bash npm run test:templates ``` ### MCP Tools The following tools are available via MCP: - `list_node_templates(nodeTypes, limit)` - Find templates using specific nodes - `get_template(templateId)` - Get complete workflow JSON - `search_templates(query, limit)` - Search by keywords - `get_templates_for_task(task)` - Get templates for common tasks ### Task Categories - `ai_automation` - AI-powered workflows - `data_sync` - Database and spreadsheet synchronization - `webhook_processing` - Webhook handling workflows - `email_automation` - Email processing workflows - `slack_integration` - Slack bots and notifications - `data_transformation` - Data manipulation workflows - `file_processing` - File handling workflows - `scheduling` - Scheduled and recurring tasks - `api_integration` - External API connections - `database_operations` - Database CRUD operations ## Implementation Details ### Architecture - `template-fetcher.ts` - Handles API communication and rate limiting - `template-repository.ts` - Database operations and queries - `template-service.ts` - Business logic and MCP integration ### Database Schema Templates are stored in a dedicated table with: - Workflow metadata (name, description, author) - Node usage tracking - View counts for popularity - Complete workflow JSON - Creation/update timestamps - 6-month freshness constraint ### API Endpoints Used - `/api/templates/workflows` - List all workflows - `/api/templates/search` - Search with pagination - `/api/templates/workflows/{id}` - Get specific workflow - `/api/templates/search/filters` - Available filters ## Notes - Templates are NOT fetched during regular database rebuilds - Run `fetch:templates` manually when you need fresh templates - API rate limiting is implemented (200-500ms between requests) - Progress is shown during fetching for large datasets ``` -------------------------------------------------------------------------------- /tests/benchmarks/README.md: -------------------------------------------------------------------------------- ```markdown # Performance Benchmarks This directory contains performance benchmarks for critical operations in the n8n-mcp project. ## Running Benchmarks ### Local Development ```bash # Run all benchmarks npm run benchmark # Watch mode for development npm run benchmark:watch # Interactive UI npm run benchmark:ui # Run specific benchmark file npx vitest bench tests/benchmarks/node-loading.bench.ts ``` ### CI/CD Benchmarks run automatically on: - Every push to `main` branch - Every pull request - Manual workflow dispatch ## Benchmark Suites ### 1. Node Loading Performance (`node-loading.bench.ts`) - Package loading (n8n-nodes-base, @n8n/n8n-nodes-langchain) - Individual node file loading - Package.json parsing ### 2. Database Query Performance (`database-queries.bench.ts`) - Node retrieval by type - Category filtering - Search operations (OR, AND, FUZZY modes) - Node counting and statistics - Insert/update operations ### 3. Search Operations (`search-operations.bench.ts`) - Single and multi-word searches - Exact phrase matching - Fuzzy search performance - Property search within nodes - Complex filtering operations ### 4. Validation Performance (`validation-performance.bench.ts`) - Node configuration validation (minimal, strict, ai-friendly) - Expression validation - Workflow validation - Property dependency resolution ### 5. MCP Tool Execution (`mcp-tools.bench.ts`) - Tool execution overhead - Response formatting - Complex query handling ## Performance Targets | Operation | Target | Alert Threshold | |-----------|--------|-----------------| | Node loading | <100ms per package | >150ms | | Database query | <5ms per query | >10ms | | Search (simple) | <10ms | >20ms | | Search (complex) | <50ms | >100ms | | Validation (simple) | <1ms | >2ms | | Validation (complex) | <10ms | >20ms | | MCP tool execution | <50ms | >100ms | ## Benchmark Results - Results are tracked over time using GitHub Actions - Historical data available at: https://czlonkowski.github.io/n8n-mcp/benchmarks/ - Performance regressions >10% trigger automatic alerts - PR comments show benchmark comparisons ## Writing New Benchmarks ```typescript import { bench, describe } from 'vitest'; describe('My Performance Suite', () => { bench('operation name', async () => { // Code to benchmark }, { iterations: 100, // Number of times to run warmupIterations: 10, // Warmup runs (not measured) warmupTime: 500, // Warmup duration in ms time: 3000 // Total benchmark duration in ms }); }); ``` ## Best Practices 1. **Isolate Operations**: Benchmark specific operations, not entire workflows 2. **Use Realistic Data**: Load actual n8n nodes for realistic measurements 3. **Warmup**: Always include warmup iterations to avoid JIT compilation effects 4. **Memory**: Use in-memory databases for consistent results 5. **Iterations**: Balance between accuracy and execution time ## Troubleshooting ### Inconsistent Results - Increase `warmupIterations` and `warmupTime` - Run benchmarks in isolation - Check for background processes ### Memory Issues - Reduce `iterations` for memory-intensive operations - Add cleanup in `afterEach` hooks - Monitor memory usage during benchmarks ### CI Failures - Check benchmark timeout settings - Verify GitHub Actions runner resources - Review alert thresholds for false positives ``` -------------------------------------------------------------------------------- /tests/unit/__mocks__/README.md: -------------------------------------------------------------------------------- ```markdown # n8n-nodes-base Mock This directory contains comprehensive mocks for n8n packages used in unit tests. ## n8n-nodes-base Mock The `n8n-nodes-base.ts` mock provides a complete testing infrastructure for code that depends on n8n nodes. ### Features 1. **Pre-configured Node Types** - `webhook` - Trigger node with webhook functionality - `httpRequest` - HTTP request node with mock responses - `slack` - Slack integration with all resources and operations - `function` - JavaScript code execution node - `noOp` - Pass-through utility node - `merge` - Data stream merging node - `if` - Conditional branching node - `switch` - Multi-output routing node 2. **Flexible Mock Behavior** - Override node execution logic - Customize node descriptions - Add custom nodes dynamically - Reset all mocks between tests ### Basic Usage ```typescript import { vi } from 'vitest'; // Mock the module vi.mock('n8n-nodes-base', () => import('../__mocks__/n8n-nodes-base')); // In your test import { getNodeTypes, mockNodeBehavior, resetAllMocks } from '../__mocks__/n8n-nodes-base'; describe('Your test', () => { beforeEach(() => { resetAllMocks(); }); it('should get node description', () => { const registry = getNodeTypes(); const slackNode = registry.getByName('slack'); expect(slackNode?.description.name).toBe('slack'); }); }); ``` ### Advanced Usage #### Override Node Behavior ```typescript mockNodeBehavior('httpRequest', { execute: async function(this: IExecuteFunctions) { return [[{ json: { custom: 'response' } }]]; } }); ``` #### Add Custom Nodes ```typescript import { registerMockNode } from '../__mocks__/n8n-nodes-base'; const customNode = { description: { displayName: 'Custom Node', name: 'customNode', group: ['transform'], version: 1, description: 'A custom test node', defaults: { name: 'Custom' }, inputs: ['main'], outputs: ['main'], properties: [] }, execute: async function() { return [[{ json: { result: 'custom' } }]]; } }; registerMockNode('customNode', customNode); ``` #### Mock Execution Context ```typescript const mockContext = { getInputData: vi.fn(() => [{ json: { test: 'data' } }]), getNodeParameter: vi.fn((name: string) => { const params = { method: 'POST', url: 'https://api.example.com' }; return params[name]; }), getCredentials: vi.fn(async () => ({ apiKey: 'test-key' })), helpers: { returnJsonArray: vi.fn(), httpRequest: vi.fn() } }; const result = await node.execute.call(mockContext); ``` ### Mock Structure Each mock node implements the `INodeType` interface with: - `description`: Complete node metadata including properties, inputs/outputs, credentials - `execute`: Mock implementation for regular nodes (returns `INodeExecutionData[][]`) - `webhook`: Mock implementation for trigger nodes (returns webhook data) ### Testing Patterns 1. **Unit Testing Node Logic** ```typescript const node = registry.getByName('slack'); const result = await node.execute.call(mockContext); expect(result[0][0].json.ok).toBe(true); ``` 2. **Testing Node Properties** ```typescript const node = registry.getByName('httpRequest'); const methodProp = node.description.properties.find(p => p.name === 'method'); expect(methodProp.options).toHaveLength(6); ``` 3. **Testing Conditional Nodes** ```typescript const ifNode = registry.getByName('if'); const [trueOutput, falseOutput] = await ifNode.execute.call(mockContext); expect(trueOutput).toHaveLength(2); expect(falseOutput).toHaveLength(1); ``` ### Utilities - `resetAllMocks()` - Clear all mock function calls - `mockNodeBehavior(name, overrides)` - Override specific node behavior - `registerMockNode(name, node)` - Add new mock nodes - `getNodeTypes()` - Get the node registry with `getByName` and `getByNameAndVersion` ### See Also - `tests/unit/examples/using-n8n-nodes-base-mock.test.ts` - Complete usage examples - `tests/unit/__mocks__/n8n-nodes-base.test.ts` - Mock test coverage ``` -------------------------------------------------------------------------------- /tests/mocks/README.md: -------------------------------------------------------------------------------- ```markdown # MSW (Mock Service Worker) Setup for n8n API This directory contains the MSW infrastructure for mocking n8n API responses in tests. ## Structure ``` mocks/ ├── n8n-api/ │ ├── handlers.ts # Default MSW handlers for n8n API endpoints │ ├── data/ # Mock data for responses │ │ ├── workflows.ts # Mock workflow data and factories │ │ ├── executions.ts # Mock execution data and factories │ │ └── credentials.ts # Mock credential data │ └── index.ts # Central exports ``` ## Usage ### Basic Usage (Automatic) MSW is automatically initialized for all tests via `vitest.config.ts`. The default handlers will intercept all n8n API requests. ```typescript // Your test file import { describe, it, expect } from 'vitest'; import { N8nApiClient } from '@/services/n8n-api-client'; describe('My Integration Test', () => { it('should work with mocked n8n API', async () => { const client = new N8nApiClient({ baseUrl: 'http://localhost:5678' }); // This will hit the MSW mock, not the real API const workflows = await client.getWorkflows(); expect(workflows).toBeDefined(); }); }); ``` ### Custom Handlers for Specific Tests ```typescript import { useHandlers, http, HttpResponse } from '@tests/setup/msw-setup'; it('should handle custom response', async () => { // Add custom handler for this test only useHandlers( http.get('*/api/v1/workflows', () => { return HttpResponse.json({ data: [{ id: 'custom-workflow', name: 'Custom' }] }); }) ); // Your test code here }); ``` ### Using Factory Functions ```typescript import { workflowFactory, executionFactory } from '@tests/mocks/n8n-api'; it('should test with factory data', async () => { const workflow = workflowFactory.simple('n8n-nodes-base.httpRequest', { method: 'POST', url: 'https://example.com/api' }); useHandlers( http.get('*/api/v1/workflows/test-id', () => { return HttpResponse.json({ data: workflow }); }) ); // Your test code here }); ``` ### Integration Test Server For integration tests that need more control: ```typescript import { mswTestServer, n8nApiMock } from '@tests/integration/setup/msw-test-server'; describe('Integration Tests', () => { beforeAll(() => { mswTestServer.start({ onUnhandledRequest: 'error' }); }); afterAll(() => { mswTestServer.stop(); }); afterEach(() => { mswTestServer.reset(); }); it('should test workflow creation', async () => { // Use helper to mock workflow creation mswTestServer.use( n8nApiMock.mockWorkflowCreate({ id: 'new-workflow', name: 'Created Workflow' }) ); // Your test code here }); }); ``` ### Debugging Enable MSW debug logging: ```bash MSW_DEBUG=true npm test ``` This will log all intercepted requests and responses. ### Best Practices 1. **Use factories for test data**: Don't hardcode test data, use the provided factories 2. **Reset handlers between tests**: This is done automatically, but be aware of it 3. **Be specific with handlers**: Use specific URLs/patterns to avoid conflicts 4. **Test error scenarios**: Use the error helpers to test error handling 5. **Verify unhandled requests**: In integration tests, verify no unexpected requests were made ### Common Patterns #### Testing Success Scenarios ```typescript useHandlers( http.get('*/api/v1/workflows/:id', ({ params }) => { return HttpResponse.json({ data: workflowFactory.custom({ id: params.id as string }) }); }) ); ``` #### Testing Error Scenarios ```typescript useHandlers( http.get('*/api/v1/workflows/:id', () => { return HttpResponse.json( { message: 'Not found', code: 'NOT_FOUND' }, { status: 404 } ); }) ); ``` #### Testing Pagination ```typescript const workflows = Array.from({ length: 150 }, (_, i) => workflowFactory.custom({ id: `workflow_${i}` }) ); useHandlers( http.get('*/api/v1/workflows', ({ request }) => { const url = new URL(request.url); const limit = parseInt(url.searchParams.get('limit') || '100'); const cursor = url.searchParams.get('cursor'); const start = cursor ? parseInt(cursor) : 0; const data = workflows.slice(start, start + limit); return HttpResponse.json({ data, nextCursor: start + limit < workflows.length ? String(start + limit) : null }); }) ); ``` ``` -------------------------------------------------------------------------------- /tests/utils/README.md: -------------------------------------------------------------------------------- ```markdown # Test Database Utilities This directory contains comprehensive database testing utilities for the n8n-mcp project. These utilities simplify database setup, data seeding, and state management in tests. ## Overview The `database-utils.ts` file provides a complete set of utilities for: - Creating test databases (in-memory or file-based) - Seeding test data (nodes and templates) - Managing database state (snapshots, resets) - Loading fixtures from JSON files - Helper functions for common database operations ## Quick Start ```typescript import { createTestDatabase, seedTestNodes, dbHelpers } from '../utils/database-utils'; describe('My Test', () => { let testDb; afterEach(async () => { if (testDb) await testDb.cleanup(); }); it('should test something', async () => { // Create in-memory database testDb = await createTestDatabase(); // Seed test data await seedTestNodes(testDb.nodeRepository); // Run your tests const node = testDb.nodeRepository.getNode('nodes-base.httpRequest'); expect(node).toBeDefined(); }); }); ``` ## Main Functions ### createTestDatabase(options?) Creates a test database with repositories. Options: - `inMemory` (boolean, default: true) - Use in-memory SQLite - `dbPath` (string) - Custom path for file-based database - `initSchema` (boolean, default: true) - Initialize database schema - `enableFTS5` (boolean, default: false) - Enable full-text search ### seedTestNodes(repository, nodes?) Seeds test nodes into the database. Includes 3 default nodes (httpRequest, webhook, slack) plus any custom nodes provided. ### seedTestTemplates(repository, templates?) Seeds test templates into the database. Includes 2 default templates plus any custom templates provided. ### createTestNode(overrides?) Creates a test node with sensible defaults that can be overridden. ### createTestTemplate(overrides?) Creates a test template with sensible defaults that can be overridden. ### resetDatabase(adapter) Drops all tables and reinitializes the schema. ### createDatabaseSnapshot(adapter) Creates a snapshot of the current database state. ### restoreDatabaseSnapshot(adapter, snapshot) Restores database to a previous snapshot state. ### loadFixtures(adapter, fixturePath) Loads nodes and templates from a JSON fixture file. ## Database Helpers (dbHelpers) - `countRows(adapter, table)` - Count rows in a table - `nodeExists(adapter, nodeType)` - Check if a node exists - `getAllNodeTypes(adapter)` - Get all node type strings - `clearTable(adapter, table)` - Clear all rows from a table - `executeSql(adapter, sql)` - Execute raw SQL ## Testing Patterns ### Unit Tests (In-Memory Database) ```typescript const testDb = await createTestDatabase(); // Fast, isolated ``` ### Integration Tests (File Database) ```typescript const testDb = await createTestDatabase({ inMemory: false, dbPath: './test.db' }); ``` ### Using Fixtures ```typescript await loadFixtures(testDb.adapter, './fixtures/complex-scenario.json'); ``` ### State Management with Snapshots ```typescript // Save current state const snapshot = await createDatabaseSnapshot(testDb.adapter); // Do risky operations... // Restore if needed await restoreDatabaseSnapshot(testDb.adapter, snapshot); ``` ### Transaction Testing ```typescript await withTransaction(testDb.adapter, async () => { // Operations here will be rolled back testDb.nodeRepository.saveNode(node); }); ``` ### Performance Testing ```typescript const duration = await measureDatabaseOperation('Bulk Insert', async () => { // Insert many nodes }); expect(duration).toBeLessThan(1000); ``` ## Fixture Format JSON fixtures should follow this format: ```json { "nodes": [ { "nodeType": "nodes-base.example", "displayName": "Example Node", "description": "Description", "category": "Category", "isAITool": false, "isTrigger": false, "isWebhook": false, "properties": [], "credentials": [], "operations": [], "version": "1", "isVersioned": false, "packageName": "n8n-nodes-base" } ], "templates": [ { "id": 1001, "name": "Template Name", "description": "Template description", "workflow": { ... }, "nodes": [ ... ], "categories": [ ... ] } ] } ``` ## Best Practices 1. **Always cleanup**: Use `afterEach` to call `testDb.cleanup()` 2. **Use in-memory for unit tests**: Faster and isolated 3. **Use snapshots for complex scenarios**: Easy rollback 4. **Seed minimal data**: Only what's needed for the test 5. **Use fixtures for complex scenarios**: Reusable test data 6. **Test both empty and populated states**: Edge cases matter ## TypeScript Support All utilities are fully typed. Import types as needed: ```typescript import type { TestDatabase, TestDatabaseOptions, DatabaseSnapshot } from '../utils/database-utils'; ``` ## Examples See `tests/examples/using-database-utils.test.ts` for comprehensive examples of all features. ``` -------------------------------------------------------------------------------- /tests/integration/ai-validation/README.md: -------------------------------------------------------------------------------- ```markdown # AI Validation Integration Tests Comprehensive integration tests for AI workflow validation introduced in v2.17.0. ## Overview These tests validate ALL AI validation operations against a REAL n8n instance. They verify: - AI Agent validation rules - Chat Trigger validation constraints - Basic LLM Chain validation requirements - AI Tool sub-node validation (HTTP Request, Code, Vector Store, Workflow, Calculator) - End-to-end workflow validation - Multi-error detection - Node type normalization (bug fix validation) ## Test Files ### 1. `helpers.ts` Utility functions for creating AI workflow components: - `createAIAgentNode()` - AI Agent with configurable options - `createChatTriggerNode()` - Chat Trigger with streaming modes - `createBasicLLMChainNode()` - Basic LLM Chain - `createLanguageModelNode()` - OpenAI/Anthropic models - `createHTTPRequestToolNode()` - HTTP Request Tool - `createCodeToolNode()` - Code Tool - `createVectorStoreToolNode()` - Vector Store Tool - `createWorkflowToolNode()` - Workflow Tool - `createCalculatorToolNode()` - Calculator Tool - `createMemoryNode()` - Buffer Window Memory - `createRespondNode()` - Respond to Webhook - `createAIConnection()` - AI connection helper (reversed for langchain) - `createMainConnection()` - Standard n8n connection - `mergeConnections()` - Merge multiple connection objects - `createAIWorkflow()` - Complete workflow builder ### 2. `ai-agent-validation.test.ts` (7 tests) Tests AI Agent validation: - ✅ Detects missing language model (MISSING_LANGUAGE_MODEL error) - ✅ Validates AI Agent with language model connected - ✅ Detects tool connections correctly (no false warnings) - ✅ Validates streaming mode constraints (Chat Trigger) - ✅ Validates AI Agent own streamResponse setting - ✅ Detects multiple memory connections (error) - ✅ Validates complete AI workflow (all components) ### 3. `chat-trigger-validation.test.ts` (5 tests) Tests Chat Trigger validation: - ✅ Detects streaming to non-AI-Agent (STREAMING_WRONG_TARGET error) - ✅ Detects missing connections (MISSING_CONNECTIONS error) - ✅ Validates valid streaming setup - ✅ Validates lastNode mode with AI Agent - ✅ Detects streaming agent with output connection ### 4. `llm-chain-validation.test.ts` (6 tests) Tests Basic LLM Chain validation: - ✅ Detects missing language model (MISSING_LANGUAGE_MODEL error) - ✅ Detects missing prompt text (MISSING_PROMPT_TEXT error) - ✅ Validates complete LLM Chain - ✅ Validates LLM Chain with memory - ✅ Detects multiple language models (error - no fallback support) - ✅ Detects tools connection (TOOLS_NOT_SUPPORTED error) ### 5. `ai-tool-validation.test.ts` (9 tests) Tests AI Tool validation: **HTTP Request Tool:** - ✅ Detects missing toolDescription (MISSING_TOOL_DESCRIPTION) - ✅ Detects missing URL (MISSING_URL) - ✅ Validates valid HTTP Request Tool **Code Tool:** - ✅ Detects missing code (MISSING_CODE) - ✅ Validates valid Code Tool **Vector Store Tool:** - ✅ Detects missing toolDescription - ✅ Validates valid Vector Store Tool **Workflow Tool:** - ✅ Detects missing workflowId (MISSING_WORKFLOW_ID) - ✅ Validates valid Workflow Tool **Calculator Tool:** - ✅ Validates Calculator Tool (no configuration needed) ### 6. `e2e-validation.test.ts` (5 tests) End-to-end validation tests: - ✅ Validates and creates complex AI workflow (7 nodes, all components) - ✅ Detects multiple validation errors (5+ errors in one workflow) - ✅ Validates streaming workflow without main output - ✅ Validates non-streaming workflow with main output - ✅ Tests node type normalization (v2.17.0 bug fix validation) ## Running Tests ### Run All AI Validation Tests ```bash npm test -- tests/integration/ai-validation --run ``` ### Run Specific Test Suite ```bash npm test -- tests/integration/ai-validation/ai-agent-validation.test.ts --run npm test -- tests/integration/ai-validation/chat-trigger-validation.test.ts --run npm test -- tests/integration/ai-validation/llm-chain-validation.test.ts --run npm test -- tests/integration/ai-validation/ai-tool-validation.test.ts --run npm test -- tests/integration/ai-validation/e2e-validation.test.ts --run ``` ### Prerequisites 1. **n8n Instance**: Real n8n instance required (not mocked) 2. **Environment Variables**: ```env N8N_API_URL=http://localhost:5678 N8N_API_KEY=your-api-key TEST_CLEANUP=true # Auto-cleanup test workflows (default: true) ``` 3. **Build**: Run `npm run build` before testing ## Test Infrastructure ### Cleanup - All tests use `TestContext` for automatic workflow cleanup - Workflows are tagged with `mcp-integration-test` and `ai-validation` - Cleanup runs in `afterEach` hooks - Orphaned workflow cleanup runs in `afterAll` (non-CI only) ### Workflow Naming - All test workflows use timestamps: `[MCP-TEST] Description 1696723200000` - Prevents name collisions - Easy identification in n8n UI ### Connection Patterns - **Main connections**: Standard n8n flow (A → B) - **AI connections**: Reversed flow (Language Model → AI Agent) - Uses helper functions to ensure correct connection structure ## Key Validation Checks ### AI Agent - Language model connections (1 or 2 for fallback) - Output parser configuration - Prompt type validation (auto vs define) - System message recommendations - Streaming mode constraints (CRITICAL) - Memory connections (0-1 max) - Tool connections - maxIterations validation ### Chat Trigger - responseMode validation (streaming vs lastNode) - Streaming requires AI Agent target - AI Agent in streaming mode: NO main output allowed ### Basic LLM Chain - Exactly 1 language model (no fallback) - Memory connections (0-1 max) - No tools support (error if connected) - Prompt configuration validation ### AI Tools - HTTP Request Tool: requires toolDescription + URL - Code Tool: requires jsCode - Vector Store Tool: requires toolDescription + vector store connection - Workflow Tool: requires workflowId - Calculator Tool: no configuration required ## Validation Error Codes Tests verify these error codes are correctly detected: - `MISSING_LANGUAGE_MODEL` - No language model connected - `MISSING_TOOL_DESCRIPTION` - Tool missing description - `MISSING_URL` - HTTP tool missing URL - `MISSING_CODE` - Code tool missing code - `MISSING_WORKFLOW_ID` - Workflow tool missing ID - `MISSING_PROMPT_TEXT` - Prompt type=define but no text - `MISSING_CONNECTIONS` - Chat Trigger has no output - `STREAMING_WITH_MAIN_OUTPUT` - AI Agent in streaming mode with main output - `STREAMING_WRONG_TARGET` - Chat Trigger streaming to non-AI-Agent - `STREAMING_AGENT_HAS_OUTPUT` - Streaming agent has output connection - `MULTIPLE_LANGUAGE_MODELS` - LLM Chain with multiple models - `MULTIPLE_MEMORY_CONNECTIONS` - Multiple memory connected - `TOOLS_NOT_SUPPORTED` - Basic LLM Chain with tools - `TOO_MANY_LANGUAGE_MODELS` - AI Agent with 3+ models - `FALLBACK_MISSING_SECOND_MODEL` - needsFallback=true but 1 model - `MULTIPLE_OUTPUT_PARSERS` - Multiple output parsers ## Bug Fix Validation ### v2.17.0 Node Type Normalization Test 5 in `e2e-validation.test.ts` validates the fix for node type normalization: - Creates AI Agent + OpenAI Model + HTTP Request Tool - Connects tool via ai_tool connection - Verifies NO false "no tools connected" warning - Validates workflow is valid This test would have caught the bug where: ```typescript // BUG: Incorrect comparison sourceNode.type === 'nodes-langchain.chatTrigger' // ❌ Never matches // FIX: Use normalizer NodeTypeNormalizer.normalizeToFullForm(sourceNode.type) === 'nodes-langchain.chatTrigger' // ✅ Works ``` ## Success Criteria All tests should: - ✅ Create workflows in real n8n - ✅ Validate using actual MCP tools (handleValidateWorkflow) - ✅ Verify validation results match expected outcomes - ✅ Clean up after themselves (no orphaned workflows) - ✅ Run in under 30 seconds each - ✅ Be deterministic (no flakiness) ## Test Coverage Total: **32 tests** covering: - **7 AI Agent tests** - Complete AI Agent validation logic - **5 Chat Trigger tests** - Streaming mode and connection validation - **6 Basic LLM Chain tests** - LLM Chain constraints and requirements - **9 AI Tool tests** - All AI tool sub-node types - **5 E2E tests** - Complex workflows and multi-error detection ## Coverage Summary ### Validation Features Tested - ✅ Language model connections (required, fallback) - ✅ Output parser configuration - ✅ Prompt type validation - ✅ System message checks - ✅ Streaming mode constraints - ✅ Memory connections (single) - ✅ Tool connections - ✅ maxIterations validation - ✅ Chat Trigger modes (streaming, lastNode) - ✅ Tool description requirements - ✅ Tool-specific parameters (URL, code, workflowId) - ✅ Multi-error detection - ✅ Node type normalization - ✅ Connection validation (missing, invalid) ### Edge Cases Tested - ✅ Empty/missing required fields - ✅ Invalid configurations - ✅ Multiple connections (when not allowed) - ✅ Streaming with main output (forbidden) - ✅ Tool connections to non-agent nodes - ✅ Fallback model configuration - ✅ Complex workflows with all components ## Recommendations ### Additional Tests (Future) 1. **Performance tests** - Validate large AI workflows (20+ nodes) 2. **Credential validation** - Test with invalid/missing credentials 3. **Expression validation** - Test n8n expressions in AI node parameters 4. **Cross-version tests** - Test different node typeVersions 5. **Concurrent validation** - Test multiple workflows in parallel ### Test Maintenance - Update tests when new AI nodes are added - Add tests for new validation rules - Keep helpers.ts updated with new node types - Verify error codes match specification ## Notes - Tests create real workflows in n8n (not mocked) - Each test is independent (no shared state) - Workflows are automatically cleaned up - Tests use actual MCP validation handlers - All AI connection types are tested - Streaming mode validation is comprehensive - Node type normalization is validated ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # n8n-MCP [](https://opensource.org/licenses/MIT) [](https://github.com/czlonkowski/n8n-mcp) [](https://www.npmjs.com/package/n8n-mcp) [](https://codecov.io/gh/czlonkowski/n8n-mcp) [](https://github.com/czlonkowski/n8n-mcp/actions) [](https://github.com/n8n-io/n8n) [](https://github.com/czlonkowski/n8n-mcp/pkgs/container/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 525+ workflow automation nodes. ## 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: - 📚 **536 n8n nodes** from both n8n-nodes-base and @n8n/n8n-nodes-langchain - 🔧 **Node properties** - 99% coverage with detailed schemas - ⚡ **Node operations** - 63.6% coverage of available actions - 📄 **Documentation** - 90% coverage from official n8n docs (including AI nodes) - 🤖 **AI tools** - 263 AI-capable nodes detected with full documentation - 💡 **Real-world examples** - 2,646 pre-extracted configurations from popular templates - 🎯 **Template library** - 2,500+ workflow templates with smart filtering ## ⚠️ Important Safety Warning **NEVER edit your production workflows directly with AI!** Always: - 🔄 **Make a copy** of your workflow before using AI tools - 🧪 **Test in development** environment first - 💾 **Export backups** of important workflows - ⚡ **Validate changes** before deploying to production AI results can be unpredictable. Protect your work! ## 🚀 Quick Start Get n8n-MCP running in 5 minutes: [](https://youtu.be/5CccjiLLyaY?si=Z62SBGlw9G34IQnQ&t=343) ### Option 1: npx (Fastest - No Installation!) 🚀 **Prerequisites:** [Node.js](https://nodejs.org/) installed on your system ```bash # Run directly with npx (no installation needed!) npx n8n-mcp ``` Add to Claude Desktop config: **Basic configuration (documentation tools only):** ```json { "mcpServers": { "n8n-mcp": { "command": "npx", "args": ["n8n-mcp"], "env": { "MCP_MODE": "stdio", "LOG_LEVEL": "error", "DISABLE_CONSOLE_OUTPUT": "true" } } } } ``` **Full configuration (with n8n management tools):** ```json { "mcpServers": { "n8n-mcp": { "command": "npx", "args": ["n8n-mcp"], "env": { "MCP_MODE": "stdio", "LOG_LEVEL": "error", "DISABLE_CONSOLE_OUTPUT": "true", "N8N_API_URL": "https://your-n8n-instance.com", "N8N_API_KEY": "your-api-key" } } } } ``` > **Note**: npx will download and run the latest version automatically. The package includes a pre-built database with all n8n node information. **Configuration file locations:** - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` **Restart Claude Desktop after updating configuration** - That's it! 🎉 ### Option 2: Docker (Easy & Isolated) 🐳 **Prerequisites:** Docker installed on your system <details> <summary><strong>📦 Install Docker</strong> (click to expand)</summary> **macOS:** ```bash # Using Homebrew brew install --cask docker # Or download from https://www.docker.com/products/docker-desktop/ ``` **Linux (Ubuntu/Debian):** ```bash # Update package index sudo apt-get update # Install Docker sudo apt-get install docker.io # Start Docker service sudo systemctl start docker sudo systemctl enable docker # Add your user to docker group (optional, to run without sudo) sudo usermod -aG docker $USER # Log out and back in for this to take effect ``` **Windows:** ```bash # Option 1: Using winget (Windows Package Manager) winget install Docker.DockerDesktop # Option 2: Using Chocolatey choco install docker-desktop # Option 3: Download installer from https://www.docker.com/products/docker-desktop/ ``` **Verify installation:** ```bash docker --version ``` </details> ```bash # Pull the Docker image (~280MB, no n8n dependencies!) docker pull ghcr.io/czlonkowski/n8n-mcp:latest ``` > **⚡ Ultra-optimized:** Our Docker image is 82% smaller than typical n8n images because it contains NO n8n dependencies - just the runtime MCP server with a pre-built database! Add to Claude Desktop config: **Basic configuration (documentation tools only):** ```json { "mcpServers": { "n8n-mcp": { "command": "docker", "args": [ "run", "-i", "--rm", "--init", "-e", "MCP_MODE=stdio", "-e", "LOG_LEVEL=error", "-e", "DISABLE_CONSOLE_OUTPUT=true", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` **Full configuration (with n8n management tools):** ```json { "mcpServers": { "n8n-mcp": { "command": "docker", "args": [ "run", "-i", "--rm", "--init", "-e", "MCP_MODE=stdio", "-e", "LOG_LEVEL=error", "-e", "DISABLE_CONSOLE_OUTPUT=true", "-e", "N8N_API_URL=https://your-n8n-instance.com", "-e", "N8N_API_KEY=your-api-key", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` >💡 Tip: If you're running n8n locally on the same machine (e.g., via Docker), use http://host.docker.internal:5678 as the N8N_API_URL. > **Note**: The n8n API credentials are optional. Without them, you'll have access to all documentation and validation tools. With them, you'll additionally get workflow management capabilities (create, update, execute workflows). ### 🏠 Local n8n Instance Configuration If you're running n8n locally (e.g., `http://localhost:5678` or Docker), you need to allow localhost webhooks: ```json { "mcpServers": { "n8n-mcp": { "command": "docker", "args": [ "run", "-i", "--rm", "--init", "-e", "MCP_MODE=stdio", "-e", "LOG_LEVEL=error", "-e", "DISABLE_CONSOLE_OUTPUT=true", "-e", "N8N_API_URL=http://host.docker.internal:5678", "-e", "N8N_API_KEY=your-api-key", "-e", "WEBHOOK_SECURITY_MODE=moderate", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` > ⚠️ **Important:** Set `WEBHOOK_SECURITY_MODE=moderate` to allow webhooks to your local n8n instance. This is safe for local development while still blocking private networks and cloud metadata. **Important:** The `-i` flag is required for MCP stdio communication. > 🔧 If you encounter any issues with Docker, check our [Docker Troubleshooting Guide](./docs/DOCKER_TROUBLESHOOTING.md). **Configuration file locations:** - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` **Restart Claude Desktop after updating configuration** - That's it! 🎉 ## 🔐 Privacy & Telemetry n8n-mcp collects anonymous usage statistics to improve the tool. [View our privacy policy](./PRIVACY.md). ### Opting Out **For npx users:** ```bash npx n8n-mcp telemetry disable ``` **For Docker users:** Add the following environment variable to your Docker configuration: ```json "-e", "N8N_MCP_TELEMETRY_DISABLED=true" ``` Example in Claude Desktop config: ```json { "mcpServers": { "n8n-mcp": { "command": "docker", "args": [ "run", "-i", "--rm", "--init", "-e", "MCP_MODE=stdio", "-e", "LOG_LEVEL=error", "-e", "N8N_MCP_TELEMETRY_DISABLED=true", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` **For docker-compose users:** Set in your environment file or docker-compose.yml: ```yaml environment: N8N_MCP_TELEMETRY_DISABLED: "true" ``` ## 💖 Support This Project <div align="center"> <a href="https://github.com/sponsors/czlonkowski"> <img src="https://img.shields.io/badge/Sponsor-❤️-db61a2?style=for-the-badge&logo=github-sponsors" alt="Sponsor n8n-mcp" /> </a> </div> **n8n-mcp** started as a personal tool but now helps tens of thousands of developers automate their workflows efficiently. Maintaining and developing this project competes with my paid work. Your sponsorship helps me: - 🚀 Dedicate focused time to new features - 🐛 Respond quickly to issues - 📚 Keep documentation up-to-date - 🔄 Ensure compatibility with latest n8n releases Every sponsorship directly translates to hours invested in making n8n-mcp better for everyone. **[Become a sponsor →](https://github.com/sponsors/czlonkowski)** --- ### Option 3: Local Installation (For Development) **Prerequisites:** [Node.js](https://nodejs.org/) installed on your system ```bash # 1. Clone and setup git clone https://github.com/czlonkowski/n8n-mcp.git cd n8n-mcp npm install npm run build npm run rebuild # 2. Test it works npm start ``` Add to Claude Desktop config: **Basic configuration (documentation tools only):** ```json { "mcpServers": { "n8n-mcp": { "command": "node", "args": ["/absolute/path/to/n8n-mcp/dist/mcp/index.js"], "env": { "MCP_MODE": "stdio", "LOG_LEVEL": "error", "DISABLE_CONSOLE_OUTPUT": "true" } } } } ``` **Full configuration (with n8n management tools):** ```json { "mcpServers": { "n8n-mcp": { "command": "node", "args": ["/absolute/path/to/n8n-mcp/dist/mcp/index.js"], "env": { "MCP_MODE": "stdio", "LOG_LEVEL": "error", "DISABLE_CONSOLE_OUTPUT": "true", "N8N_API_URL": "https://your-n8n-instance.com", "N8N_API_KEY": "your-api-key" } } } } ``` > **Note**: The n8n API credentials can be configured either in a `.env` file (create from `.env.example`) or directly in the Claude config as shown above. > 💡 Tip: If you’re running n8n locally on the same machine (e.g., via Docker), use http://host.docker.internal:5678 as the N8N_API_URL. ### Option 4: Railway Cloud Deployment (One-Click Deploy) ☁️ **Prerequisites:** Railway account (free tier available) Deploy n8n-MCP to Railway's cloud platform with zero configuration: [](https://railway.com/deploy/n8n-mcp?referralCode=n8n-mcp) **Benefits:** - ☁️ **Instant cloud hosting** - No server setup required - 🔒 **Secure by default** - HTTPS included, auth token warnings - 🌐 **Global access** - Connect from any Claude Desktop - ⚡ **Auto-scaling** - Railway handles the infrastructure - 📊 **Built-in monitoring** - Logs and metrics included **Quick Setup:** 1. Click the "Deploy on Railway" button above 2. Sign in to Railway (or create a free account) 3. Configure your deployment (project name, region) 4. Click "Deploy" and wait ~2-3 minutes 5. Copy your deployment URL and auth token 6. Add to Claude Desktop config using the HTTPS URL > 📚 **For detailed setup instructions, troubleshooting, and configuration examples, see our [Railway Deployment Guide](./docs/RAILWAY_DEPLOYMENT.md)** **Configuration file locations:** - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` **Restart Claude Desktop after updating configuration** - That's it! 🎉 ## 🔧 n8n Integration Want to use n8n-MCP with your n8n instance? Check out our comprehensive [n8n Deployment Guide](./docs/N8N_DEPLOYMENT.md) for: - Local testing with the MCP Client Tool node - Production deployment with Docker Compose - Cloud deployment on Hetzner, AWS, and other providers - Troubleshooting and security best practices ## 💻 Connect your IDE n8n-MCP works with multiple AI-powered IDEs and tools. Choose your preferred development environment: ### [Claude Code](./docs/CLAUDE_CODE_SETUP.md) Quick setup for Claude Code CLI - just type "add this mcp server" and paste the config. ### [Visual Studio Code](./docs/VS_CODE_PROJECT_SETUP.md) Full setup guide for VS Code with GitHub Copilot integration and MCP support. ### [Cursor](./docs/CURSOR_SETUP.md) Step-by-step tutorial for connecting n8n-MCP to Cursor IDE with custom rules. ### [Windsurf](./docs/WINDSURF_SETUP.md) Complete guide for integrating n8n-MCP with Windsurf using project rules. ### [Codex](./docs/CODEX_SETUP.md) Complete guide for integrating n8n-MCP with Codex. ## 🤖 Claude Project Setup For the best results when using n8n-MCP with Claude Projects, use these enhanced system instructions: ````markdown You are an expert in n8n automation software using n8n-MCP tools. Your role is to design, build, and validate n8n workflows with maximum accuracy and efficiency. ## Core Principles ### 1. Silent Execution CRITICAL: Execute tools without commentary. Only respond AFTER all tools complete. ❌ BAD: "Let me search for Slack nodes... Great! Now let me get details..." ✅ GOOD: [Execute search_nodes and get_node_essentials in parallel, then respond] ### 2. Parallel Execution When operations are independent, execute them in parallel for maximum performance. ✅ GOOD: Call search_nodes, list_nodes, and search_templates simultaneously ❌ BAD: Sequential tool calls (await each one before the next) ### 3. Templates First ALWAYS check templates before building from scratch (2,500+ available). ### 4. Multi-Level Validation Use validate_node_minimal → validate_node_operation → validate_workflow pattern. ### 5. Never Trust Defaults ⚠️ CRITICAL: Default parameter values are the #1 source of runtime failures. ALWAYS explicitly configure ALL parameters that control node behavior. ## Workflow Process 1. **Start**: Call `tools_documentation()` for best practices 2. **Template Discovery Phase** (FIRST - parallel when searching multiple) - `search_templates_by_metadata({complexity: "simple"})` - Smart filtering - `get_templates_for_task('webhook_processing')` - Curated by task - `search_templates('slack notification')` - Text search - `list_node_templates(['n8n-nodes-base.slack'])` - By node type **Filtering strategies**: - Beginners: `complexity: "simple"` + `maxSetupMinutes: 30` - By role: `targetAudience: "marketers"` | `"developers"` | `"analysts"` - By time: `maxSetupMinutes: 15` for quick wins - By service: `requiredService: "openai"` for compatibility 3. **Node Discovery** (if no suitable template - parallel execution) - Think deeply about requirements. Ask clarifying questions if unclear. - `search_nodes({query: 'keyword', includeExamples: true})` - Parallel for multiple nodes - `list_nodes({category: 'trigger'})` - Browse by category - `list_ai_tools()` - AI-capable nodes 4. **Configuration Phase** (parallel for multiple nodes) - `get_node_essentials(nodeType, {includeExamples: true})` - 10-20 key properties - `search_node_properties(nodeType, 'auth')` - Find specific properties - `get_node_documentation(nodeType)` - Human-readable docs - Show workflow architecture to user for approval before proceeding 5. **Validation Phase** (parallel for multiple nodes) - `validate_node_minimal(nodeType, config)` - Quick required fields check - `validate_node_operation(nodeType, config, 'runtime')` - Full validation with fixes - Fix ALL errors before proceeding 6. **Building Phase** - If using template: `get_template(templateId, {mode: "full"})` - **MANDATORY ATTRIBUTION**: "Based on template by **[author.name]** (@[username]). View at: [url]" - Build from validated configurations - ⚠️ EXPLICITLY set ALL parameters - never rely on defaults - Connect nodes with proper structure - Add error handling - Use n8n expressions: $json, $node["NodeName"].json - Build in artifact (unless deploying to n8n instance) 7. **Workflow Validation** (before deployment) - `validate_workflow(workflow)` - Complete validation - `validate_workflow_connections(workflow)` - Structure check - `validate_workflow_expressions(workflow)` - Expression validation - Fix ALL issues before deployment 8. **Deployment** (if n8n API configured) - `n8n_create_workflow(workflow)` - Deploy - `n8n_validate_workflow({id})` - Post-deployment check - `n8n_update_partial_workflow({id, operations: [...]})` - Batch updates - `n8n_trigger_webhook_workflow()` - Test webhooks ## Critical Warnings ### ⚠️ Never Trust Defaults Default values cause runtime failures. Example: ```json // ❌ FAILS at runtime {resource: "message", operation: "post", text: "Hello"} // ✅ WORKS - all parameters explicit {resource: "message", operation: "post", select: "channel", channelId: "C123", text: "Hello"} ``` ### ⚠️ Example Availability `includeExamples: true` returns real configurations from workflow templates. - Coverage varies by node popularity - When no examples available, use `get_node_essentials` + `validate_node_minimal` ## Validation Strategy ### Level 1 - Quick Check (before building) `validate_node_minimal(nodeType, config)` - Required fields only (<100ms) ### Level 2 - Comprehensive (before building) `validate_node_operation(nodeType, config, 'runtime')` - Full validation with fixes ### Level 3 - Complete (after building) `validate_workflow(workflow)` - Connections, expressions, AI tools ### Level 4 - Post-Deployment 1. `n8n_validate_workflow({id})` - Validate deployed workflow 2. `n8n_autofix_workflow({id})` - Auto-fix common errors 3. `n8n_list_executions()` - Monitor execution status ## Response Format ### Initial Creation ``` [Silent tool execution in parallel] Created workflow: - Webhook trigger → Slack notification - Configured: POST /webhook → #general channel Validation: ✅ All checks passed ``` ### Modifications ``` [Silent tool execution] Updated workflow: - Added error handling to HTTP node - Fixed required Slack parameters Changes validated successfully. ``` ## Batch Operations Use `n8n_update_partial_workflow` with multiple operations in a single call: ✅ GOOD - Batch multiple operations: ```json n8n_update_partial_workflow({ id: "wf-123", operations: [ {type: "updateNode", nodeId: "slack-1", changes: {...}}, {type: "updateNode", nodeId: "http-1", changes: {...}}, {type: "cleanStaleConnections"} ] }) ``` ❌ BAD - Separate calls: ```json n8n_update_partial_workflow({id: "wf-123", operations: [{...}]}) n8n_update_partial_workflow({id: "wf-123", operations: [{...}]}) ``` ## Example Workflow ### Template-First Approach ``` // STEP 1: Template Discovery (parallel execution) [Silent execution] search_templates_by_metadata({ requiredService: 'slack', complexity: 'simple', targetAudience: 'marketers' }) get_templates_for_task('slack_integration') // STEP 2: Use template get_template(templateId, {mode: 'full'}) validate_workflow(workflow) // Response after all tools complete: "Found template by **David Ashby** (@cfomodz). View at: https://n8n.io/workflows/2414 Validation: ✅ All checks passed" ``` ### Building from Scratch (if no template) ``` // STEP 1: Discovery (parallel execution) [Silent execution] search_nodes({query: 'slack', includeExamples: true}) list_nodes({category: 'communication'}) // STEP 2: Configuration (parallel execution) [Silent execution] get_node_essentials('n8n-nodes-base.slack', {includeExamples: true}) get_node_essentials('n8n-nodes-base.webhook', {includeExamples: true}) // STEP 3: Validation (parallel execution) [Silent execution] validate_node_minimal('n8n-nodes-base.slack', config) validate_node_operation('n8n-nodes-base.slack', fullConfig, 'runtime') // STEP 4: Build // Construct workflow with validated configs // ⚠️ Set ALL parameters explicitly // STEP 5: Validate [Silent execution] validate_workflow(workflowJson) // Response after all tools complete: "Created workflow: Webhook → Slack Validation: ✅ Passed" ``` ### Batch Updates ```json // ONE call with multiple operations n8n_update_partial_workflow({ id: "wf-123", operations: [ {type: "updateNode", nodeId: "slack-1", changes: {position: [100, 200]}}, {type: "updateNode", nodeId: "http-1", changes: {position: [300, 200]}}, {type: "cleanStaleConnections"} ] }) ``` ## Important Rules ### Core Behavior 1. **Silent execution** - No commentary between tools 2. **Parallel by default** - Execute independent operations simultaneously 3. **Templates first** - Always check before building (2,500+ available) 4. **Multi-level validation** - Quick check → Full validation → Workflow validation 5. **Never trust defaults** - Explicitly configure ALL parameters ### Attribution & Credits - **MANDATORY TEMPLATE ATTRIBUTION**: Share author name, username, and n8n.io link - **Template validation** - Always validate before deployment (may need updates) ### Performance - **Batch operations** - Use diff operations with multiple changes in one call - **Parallel execution** - Search, validate, and configure simultaneously - **Template metadata** - Use smart filtering for faster discovery ### Code Node Usage - **Avoid when possible** - Prefer standard nodes - **Only when necessary** - Use code node as last resort - **AI tool capability** - ANY node can be an AI tool (not just marked ones) ### Most Popular n8n Nodes (for get_node_essentials): 1. **n8n-nodes-base.code** - JavaScript/Python scripting 2. **n8n-nodes-base.httpRequest** - HTTP API calls 3. **n8n-nodes-base.webhook** - Event-driven triggers 4. **n8n-nodes-base.set** - Data transformation 5. **n8n-nodes-base.if** - Conditional routing 6. **n8n-nodes-base.manualTrigger** - Manual workflow execution 7. **n8n-nodes-base.respondToWebhook** - Webhook responses 8. **n8n-nodes-base.scheduleTrigger** - Time-based triggers 9. **@n8n/n8n-nodes-langchain.agent** - AI agents 10. **n8n-nodes-base.googleSheets** - Spreadsheet integration 11. **n8n-nodes-base.merge** - Data merging 12. **n8n-nodes-base.switch** - Multi-branch routing 13. **n8n-nodes-base.telegram** - Telegram bot integration 14. **@n8n/n8n-nodes-langchain.lmChatOpenAi** - OpenAI chat models 15. **n8n-nodes-base.splitInBatches** - Batch processing 16. **n8n-nodes-base.openAi** - OpenAI legacy node 17. **n8n-nodes-base.gmail** - Email automation 18. **n8n-nodes-base.function** - Custom functions 19. **n8n-nodes-base.stickyNote** - Workflow documentation 20. **n8n-nodes-base.executeWorkflowTrigger** - Sub-workflow calls **Note:** LangChain nodes use the `@n8n/n8n-nodes-langchain.` prefix, core nodes use `n8n-nodes-base.` ```` Save these instructions in your Claude Project for optimal n8n workflow assistance with intelligent template discovery. ## 🚨 Important: Sharing Guidelines This project is MIT licensed and free for everyone to use. However: - **✅ DO**: Share this repository freely with proper attribution - **✅ DO**: Include a direct link to https://github.com/czlonkowski/n8n-mcp in your first post/video - **❌ DON'T**: Gate this free tool behind engagement requirements (likes, follows, comments) - **❌ DON'T**: Use this project for engagement farming on social media This tool was created to benefit everyone in the n8n community without friction. Please respect the MIT license spirit by keeping it accessible to all. ## Features - **🔍 Smart Node Search**: Find nodes by name, category, or functionality - **📖 Essential Properties**: Get only the 10-20 properties that matter - **💡 Real-World Examples**: 2,646 pre-extracted configurations from popular templates - **✅ Config Validation**: Validate node configurations before deployment - **🤖 AI Workflow Validation**: Comprehensive validation for AI Agent workflows (NEW in v2.17.0!) - Missing language model detection - AI tool connection validation - Streaming mode constraints - Memory and output parser checks - **🔗 Dependency Analysis**: Understand property relationships and conditions - **🎯 Template Discovery**: 2,500+ workflow templates with smart filtering - **⚡ Fast Response**: Average query time ~12ms with optimized SQLite - **🌐 Universal Compatibility**: Works with any Node.js version ## 💬 Why n8n-MCP? A Testimonial from Claude > *"Before MCP, I was translating. Now I'm composing. And that changes everything about how we can build automation."* When Claude, Anthropic's AI assistant, tested n8n-MCP, the results were transformative: **Without MCP:** "I was basically playing a guessing game. 'Is it `scheduleTrigger` or `schedule`? Does it take `interval` or `rule`?' I'd write what seemed logical, but n8n has its own conventions that you can't just intuit. I made six different configuration errors in a simple HackerNews scraper." **With MCP:** "Everything just... worked. Instead of guessing, I could ask `get_node_essentials()` and get exactly what I needed - not a 100KB JSON dump, but the actual 5-10 properties that matter. What took 45 minutes now takes 3 minutes." **The Real Value:** "It's about confidence. When you're building automation workflows, uncertainty is expensive. One wrong parameter and your workflow fails at 3 AM. With MCP, I could validate my configuration before deployment. That's not just time saved - that's peace of mind." [Read the full interview →](docs/CLAUDE_INTERVIEW.md) ## 📡 Available MCP Tools Once connected, Claude can use these powerful tools: ### Core Tools - **`tools_documentation`** - Get documentation for any MCP tool (START HERE!) - **`list_nodes`** - List all n8n nodes with filtering options - **`get_node_info`** - Get comprehensive information about a specific node - **`get_node_essentials`** - Get only essential properties (10-20 instead of 200+). Use `includeExamples: true` to get top 3 real-world configurations from popular templates - **`search_nodes`** - Full-text search across all node documentation. Use `includeExamples: true` to get top 2 real-world configurations per node from templates - **`search_node_properties`** - Find specific properties within nodes - **`list_ai_tools`** - List all AI-capable nodes (ANY node can be used as AI tool!) - **`get_node_as_tool_info`** - Get guidance on using any node as an AI tool ### Template Tools - **`list_templates`** - Browse all templates with descriptions and optional metadata (2,500+ templates) - **`search_templates`** - Text search across template names and descriptions - **`search_templates_by_metadata`** - Advanced filtering by complexity, setup time, services, audience - **`list_node_templates`** - Find templates using specific nodes - **`get_template`** - Get complete workflow JSON for import - **`get_templates_for_task`** - Curated templates for common automation tasks ### Validation Tools - **`validate_workflow`** - Complete workflow validation including **AI Agent validation** (NEW in v2.17.0!) - Detects missing language model connections - Validates AI tool connections (no false warnings) - Enforces streaming mode constraints - Checks memory and output parser configurations - **`validate_workflow_connections`** - Check workflow structure and AI tool connections - **`validate_workflow_expressions`** - Validate n8n expressions including $fromAI() - **`validate_node_operation`** - Validate node configurations (operation-aware, profiles support) - **`validate_node_minimal`** - Quick validation for just required fields ### Advanced Tools - **`get_property_dependencies`** - Analyze property visibility conditions - **`get_node_documentation`** - Get parsed documentation from n8n-docs - **`get_database_statistics`** - View database metrics and coverage ### n8n Management Tools (Optional - Requires API Configuration) These powerful tools allow you to manage n8n workflows directly from Claude. They're only available when you provide `N8N_API_URL` and `N8N_API_KEY` in your configuration. #### Workflow Management - **`n8n_create_workflow`** - Create new workflows with nodes and connections - **`n8n_get_workflow`** - Get complete workflow by ID - **`n8n_get_workflow_details`** - Get workflow with execution statistics - **`n8n_get_workflow_structure`** - Get simplified workflow structure - **`n8n_get_workflow_minimal`** - Get minimal workflow info (ID, name, active status) - **`n8n_update_full_workflow`** - Update entire workflow (complete replacement) - **`n8n_update_partial_workflow`** - Update workflow using diff operations (NEW in v2.7.0!) - **`n8n_delete_workflow`** - Delete workflows permanently - **`n8n_list_workflows`** - List workflows with filtering and pagination - **`n8n_validate_workflow`** - Validate workflows already in n8n by ID (NEW in v2.6.3) - **`n8n_autofix_workflow`** - Automatically fix common workflow errors (NEW in v2.13.0!) #### Execution Management - **`n8n_trigger_webhook_workflow`** - Trigger workflows via webhook URL - **`n8n_get_execution`** - Get execution details by ID - **`n8n_list_executions`** - List executions with status filtering - **`n8n_delete_execution`** - Delete execution records #### System Tools - **`n8n_health_check`** - Check n8n API connectivity and features - **`n8n_diagnostic`** - Troubleshoot management tools visibility and configuration issues - **`n8n_list_available_tools`** - List all available management tools ### Example Usage ```typescript // Get essentials with real-world examples from templates get_node_essentials({ nodeType: "nodes-base.httpRequest", includeExamples: true // Returns top 3 configs from popular templates }) // Search nodes with configuration examples search_nodes({ query: "send email gmail", includeExamples: true // Returns top 2 configs per node }) // Validate before deployment validate_node_operation({ nodeType: "nodes-base.httpRequest", config: { method: "POST", url: "..." }, profile: "runtime" // or "minimal", "ai-friendly", "strict" }) // Quick required field check validate_node_minimal({ nodeType: "nodes-base.slack", config: { resource: "message", operation: "send" } }) ``` ## 💻 Local Development Setup For contributors and advanced users: **Prerequisites:** - [Node.js](https://nodejs.org/) (any version - automatic fallback if needed) - npm or yarn - Git ```bash # 1. Clone the repository git clone https://github.com/czlonkowski/n8n-mcp.git cd n8n-mcp # 2. Clone n8n docs (optional but recommended) git clone https://github.com/n8n-io/n8n-docs.git ../n8n-docs # 3. Install and build npm install npm run build # 4. Initialize database npm run rebuild # 5. Start the server npm start # stdio mode for Claude Desktop npm run start:http # HTTP mode for remote access ``` ### Development Commands ```bash # Build & Test npm run build # Build TypeScript npm run rebuild # Rebuild node database npm run test-nodes # Test critical nodes npm run validate # Validate node data npm test # Run all tests # Update Dependencies npm run update:n8n:check # Check for n8n updates npm run update:n8n # Update n8n packages # Run Server npm run dev # Development with auto-reload npm run dev:http # HTTP dev mode ``` ## 📚 Documentation ### Setup Guides - [Installation Guide](./docs/INSTALLATION.md) - Comprehensive installation instructions - [Claude Desktop Setup](./docs/README_CLAUDE_SETUP.md) - Detailed Claude configuration - [Docker Guide](./docs/DOCKER_README.md) - Advanced Docker deployment options - [MCP Quick Start](./docs/MCP_QUICK_START_GUIDE.md) - Get started quickly with n8n-MCP ### Feature Documentation - [Workflow Diff Operations](./docs/workflow-diff-examples.md) - Token-efficient workflow updates (NEW!) - [Transactional Updates](./docs/transactional-updates-example.md) - Two-pass workflow editing - [MCP Essentials](./docs/MCP_ESSENTIALS_README.md) - AI-optimized tools guide - [Validation System](./docs/validation-improvements-v2.4.2.md) - Smart validation profiles ### Development & Deployment - [Railway Deployment](./docs/RAILWAY_DEPLOYMENT.md) - One-click cloud deployment guide - [HTTP Deployment](./docs/HTTP_DEPLOYMENT.md) - Remote server setup guide - [Dependency Management](./docs/DEPENDENCY_UPDATES.md) - Keeping n8n packages in sync - [Claude's Interview](./docs/CLAUDE_INTERVIEW.md) - Real-world impact of n8n-MCP ### Project Information - [Change Log](./CHANGELOG.md) - Complete version history - [Claude Instructions](./CLAUDE.md) - AI guidance for this codebase - [MCP Tools Reference](#-available-mcp-tools) - Complete list of available tools ## 📊 Metrics & Coverage Current database coverage (n8n v1.113.3): - ✅ **536/536** nodes loaded (100%) - ✅ **528** nodes with properties (98.7%) - ✅ **470** nodes with documentation (88%) - ✅ **267** AI-capable tools detected - ✅ **2,646** pre-extracted template configurations - ✅ **2,500+** workflow templates available - ✅ **AI Agent & LangChain nodes** fully documented - ⚡ **Average response time**: ~12ms - 💾 **Database size**: ~15MB (optimized) ## 🔄 Recent Updates See [CHANGELOG.md](./docs/CHANGELOG.md) for full version history and recent changes. ## ⚠️ Known Issues ### Claude Desktop Container Management #### Container Accumulation (Fixed in v2.7.20+) Previous versions had an issue where containers would not properly clean up when Claude Desktop sessions ended. This has been fixed in v2.7.20+ with proper signal handling. **For best container lifecycle management:** 1. **Use the --init flag** (recommended) - Docker's init system ensures proper signal handling: ```json { "mcpServers": { "n8n-mcp": { "command": "docker", "args": [ "run", "-i", "--rm", "--init", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` 2. **Ensure you're using v2.7.20 or later** - Check your version: ```bash docker run --rm ghcr.io/czlonkowski/n8n-mcp:latest --version ``` ## 🧪 Testing The project includes a comprehensive test suite with **2,883 tests** ensuring code quality and reliability: ```bash # Run all tests npm test # Run tests with coverage report npm run test:coverage # Run tests in watch mode npm run test:watch # Run specific test suites npm run test:unit # 933 unit tests npm run test:integration # 249 integration tests npm run test:bench # Performance benchmarks ``` ### Test Suite Overview - **Total Tests**: 2,883 (100% passing) - **Unit Tests**: 2,526 tests across 99 files - **Integration Tests**: 357 tests across 20 files - **Execution Time**: ~2.5 minutes in CI - **Test Framework**: Vitest (for speed and TypeScript support) - **Mocking**: MSW for API mocking, custom mocks for databases ### Coverage & Quality - **Coverage Reports**: Generated in `./coverage` directory - **CI/CD**: Automated testing on all PRs with GitHub Actions - **Performance**: Environment-aware thresholds for CI vs local - **Parallel Execution**: Configurable thread pool for faster runs ### Testing Architecture **Total: 3,336 tests** across unit and integration test suites - **Unit Tests** (2,766 tests): Isolated component testing with mocks - Services layer: Enhanced validation, property filtering, workflow validation - Parsers: Node parsing, property extraction, documentation mapping - Database: Repositories, adapters, migrations, FTS5 search - MCP tools: Tool definitions, documentation system - HTTP server: Multi-tenant support, security, configuration - **Integration Tests** (570 tests): Full system behavior validation - **n8n API Integration** (172 tests): All 18 MCP handler tools tested against real n8n instance - Workflow management: Create, read, update, delete, list, validate, autofix - Execution management: Trigger, retrieve, list, delete - System tools: Health check, tool listing, diagnostics - **MCP Protocol** (119 tests): Protocol compliance, session management, error handling - **Database** (226 tests): Repository operations, transactions, performance, FTS5 search - **Templates** (35 tests): Template fetching, storage, metadata operations - **Docker** (18 tests): Configuration, entrypoint, security validation For detailed testing documentation, see [Testing Architecture](./docs/testing-architecture.md). ## 📦 License MIT License - see [LICENSE](LICENSE) for details. **Attribution appreciated!** If you use n8n-MCP, consider: - ⭐ Starring this repository - 💬 Mentioning it in your project - 🔗 Linking back to this repo ## 🤝 Contributing Contributions are welcome! Please: 1. Fork the repository 2. Create a feature branch 3. Run tests (`npm test`) 4. Submit a pull request ### 🚀 For Maintainers: Automated Releases This project uses automated releases triggered by version changes: ```bash # Guided release preparation npm run prepare:release # Test release automation npm run test:release-automation ``` The system automatically handles: - 🏷️ GitHub releases with changelog content - 📦 NPM package publishing - 🐳 Multi-platform Docker images - 📚 Documentation updates See [Automated Release Guide](./docs/AUTOMATED_RELEASES.md) for complete details. ## 👏 Acknowledgments - [n8n](https://n8n.io) team for the workflow automation platform - [Anthropic](https://anthropic.com) for the Model Context Protocol - All contributors and users of this project ### Template Attribution All workflow templates in this project are fetched from n8n's public template gallery at [n8n.io/workflows](https://n8n.io/workflows). Each template includes: - Full attribution to the original creator (name and username) - Direct link to the source template on n8n.io - Original workflow ID for reference The AI agent instructions in this project contain mandatory attribution requirements. When using any template, the AI will automatically: - Share the template author's name and username - Provide a direct link to the original template on n8n.io - Display attribution in the format: "This workflow is based on a template by **[author]** (@[username]). View the original at: [url]" Template creators retain all rights to their workflows. This project indexes templates to improve discoverability through AI assistants. If you're a template creator and have concerns about your template being indexed, please open an issue. Special thanks to the prolific template contributors whose work helps thousands of users automate their workflows, including: **David Ashby** (@cfomodz), **Yaron Been** (@yaron-nofluff), **Jimleuk** (@jimleuk), **Davide** (@n3witalia), **David Olusola** (@dae221), **Ranjan Dailata** (@ranjancse), **Airtop** (@cesar-at-airtop), **Joseph LePage** (@joe), **Don Jayamaha Jr** (@don-the-gem-dealer), **Angel Menendez** (@djangelic), and the entire n8n community of creators! --- <div align="center"> <strong>Built with ❤️ for the n8n community</strong><br> <sub>Making AI + n8n workflow creation delightful</sub> </div> ``` -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- ```markdown # Security Policy ## Reporting Security Vulnerabilities If you discover a security vulnerability in n8n-mcp, please report it by creating a private security advisory on GitHub or emailing the maintainer directly. Please do not create public issues for security vulnerabilities. ## Security Best Practices ### 1. Environment Variables **NEVER** commit real API keys, tokens, or credentials to the repository. - Use `.env` files for local development (already in `.gitignore`) - Use `.env.example` as a template with placeholder values - Generate strong tokens using: `openssl rand -base64 32` ### 2. API Keys and Tokens - **Rotate credentials immediately** if they are exposed - Use environment variables exclusively - no hardcoded fallbacks - Implement proper token expiration when possible - Use least-privilege access for API keys ### 3. Code Security #### ❌ DON'T DO THIS: ```typescript // NEVER hardcode credentials const apiKey = process.env.N8N_API_KEY || 'n8n_api_actual_key_here'; const apiUrl = process.env.N8N_API_URL || 'https://production-url.com'; ``` #### ✅ DO THIS INSTEAD: ```typescript // Always require environment variables const apiKey = process.env.N8N_API_KEY; const apiUrl = process.env.N8N_API_URL; if (!apiKey || !apiUrl) { console.error('Error: Required environment variables are missing'); process.exit(1); } ``` ### 4. Git Security Before committing, always check: ```bash # Check for tracked sensitive files git ls-files | grep -E "\.(env|pem|key|cert)$" # Check staged changes for secrets git diff --staged | grep -iE "(api[_-]?key|secret|token|password)" ``` ### 5. Docker Security - Never include `.env` files in Docker images - Use build arguments for compile-time configuration - Use runtime environment variables for secrets - Run containers as non-root users ### 6. Dependencies - Regularly update dependencies: `npm audit` - Review dependency changes carefully - Use lock files (`package-lock.json`) - Monitor for security advisories ## Security Checklist Before each release or deployment: - [ ] No hardcoded credentials in source code - [ ] All sensitive configuration uses environment variables - [ ] `.env` files are not tracked in git - [ ] Dependencies are up to date - [ ] No sensitive data in logs - [ ] API endpoints use proper authentication - [ ] Docker images don't contain secrets ## Known Security Considerations 1. **MCP Authentication**: When running in HTTP mode, always use strong `AUTH_TOKEN` values 2. **n8n API Access**: The n8n API key provides full access to workflows - protect it carefully 3. **Database Access**: The SQLite database contains node information but no credentials ## Tools for Security - **SecureKeyGuard**: Automated scanning for exposed secrets - **npm audit**: Check for vulnerable dependencies - **git-secrets**: Prevent committing secrets to git - **dotenv-vault**: Secure environment variable management Remember: Security is everyone's responsibility. When in doubt, ask for a security review. ``` -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- ```yaml # GitHub Funding Configuration github: [czlonkowski] ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/guides/index.ts: -------------------------------------------------------------------------------- ```typescript // Export all guides export { aiAgentsGuide } from './ai-agents-guide'; ``` -------------------------------------------------------------------------------- /tests/benchmarks/index.ts: -------------------------------------------------------------------------------- ```typescript // Export all benchmark suites export * from './database-queries.bench'; export * from './mcp-tools.bench'; ``` -------------------------------------------------------------------------------- /src/utils/documentation-fetcher.ts: -------------------------------------------------------------------------------- ```typescript // Re-export everything from enhanced-documentation-fetcher export * from './enhanced-documentation-fetcher'; ``` -------------------------------------------------------------------------------- /.github/secret_scanning.yml: -------------------------------------------------------------------------------- ```yaml # Exclude database files from secret scanning # The nodes.db contains workflow templates with placeholder API keys that trigger false positives paths-ignore: - "data/nodes.db" - "data/*.db" - "nodes.db" ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/discovery/index.ts: -------------------------------------------------------------------------------- ```typescript export { searchNodesDoc } from './search-nodes'; export { listNodesDoc } from './list-nodes'; export { listAiToolsDoc } from './list-ai-tools'; export { getDatabaseStatisticsDoc } from './get-database-statistics'; ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/system/index.ts: -------------------------------------------------------------------------------- ```typescript export { toolsDocumentationDoc } from './tools-documentation'; export { n8nDiagnosticDoc } from './n8n-diagnostic'; export { n8nHealthCheckDoc } from './n8n-health-check'; export { n8nListAvailableToolsDoc } from './n8n-list-available-tools'; ``` -------------------------------------------------------------------------------- /src/telemetry/index.ts: -------------------------------------------------------------------------------- ```typescript /** * Telemetry Module * Exports for anonymous usage statistics */ export { TelemetryManager, telemetry } from './telemetry-manager'; export { TelemetryConfigManager } from './config-manager'; export { WorkflowSanitizer } from './workflow-sanitizer'; export type { TelemetryConfig } from './config-manager'; ``` -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- ```json { "extends": "./tsconfig.json", "compilerOptions": { "rootDir": "./src", // Override parent's types to exclude test-related types for production builds "types": ["node"] }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts", "tests", "types", "**/types"] } ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/templates/index.ts: -------------------------------------------------------------------------------- ```typescript export { listTasksDoc } from './list-tasks'; export { listNodeTemplatesDoc } from './list-node-templates'; export { getTemplateDoc } from './get-template'; export { searchTemplatesDoc } from './search-templates'; export { searchTemplatesByMetadataDoc } from './search-templates-by-metadata'; export { getTemplatesForTaskDoc } from './get-templates-for-task'; ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/validation/index.ts: -------------------------------------------------------------------------------- ```typescript export { validateNodeMinimalDoc } from './validate-node-minimal'; export { validateNodeOperationDoc } from './validate-node-operation'; export { validateWorkflowDoc } from './validate-workflow'; export { validateWorkflowConnectionsDoc } from './validate-workflow-connections'; export { validateWorkflowExpressionsDoc } from './validate-workflow-expressions'; ``` -------------------------------------------------------------------------------- /railway.json: -------------------------------------------------------------------------------- ```json { "build": { "builder": "DOCKERFILE", "dockerfilePath": "Dockerfile.railway" }, "deploy": { "runtime": "V2", "numReplicas": 1, "sleepApplication": false, "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 10, "volumes": [ { "mount": "/app/data", "name": "n8n-mcp-data" } ] } } ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/configuration/index.ts: -------------------------------------------------------------------------------- ```typescript export { getNodeInfoDoc } from './get-node-info'; export { getNodeEssentialsDoc } from './get-node-essentials'; export { getNodeDocumentationDoc } from './get-node-documentation'; export { searchNodePropertiesDoc } from './search-node-properties'; export { getNodeAsToolInfoDoc } from './get-node-as-tool-info'; export { getPropertyDependenciesDoc } from './get-property-dependencies'; ``` -------------------------------------------------------------------------------- /.github/gh-pages.yml: -------------------------------------------------------------------------------- ```yaml # GitHub Pages configuration for benchmark results # This file configures the gh-pages branch to serve benchmark results # Path to the benchmark data benchmarks: data_dir: benchmarks # Theme configuration theme: name: minimal # Navigation nav: - title: "Performance Benchmarks" url: /benchmarks/ - title: "Back to Repository" url: https://github.com/czlonkowski/n8n-mcp ``` -------------------------------------------------------------------------------- /tests/integration/n8n-api/utils/mcp-context.ts: -------------------------------------------------------------------------------- ```typescript import { InstanceContext } from '../../../../src/types/instance-context'; import { getN8nCredentials } from './credentials'; /** * Creates MCP context for testing MCP handlers against real n8n instance * This is what gets passed to MCP handlers (handleCreateWorkflow, etc.) */ export function createMcpContext(): InstanceContext { const creds = getN8nCredentials(); return { n8nApiUrl: creds.url, n8nApiKey: creds.apiKey }; } ``` -------------------------------------------------------------------------------- /tests/mocks/n8n-api/index.ts: -------------------------------------------------------------------------------- ```typescript /** * Central export for all n8n API mocks */ export * from './handlers'; export * from './data/workflows'; export * from './data/executions'; export * from './data/credentials'; // Re-export MSW utilities for convenience export { http, HttpResponse } from 'msw'; // Export factory utilities export { n8nHandlerFactory } from '../../setup/msw-setup'; export { n8nApiMock, testDataBuilders, mswTestServer } from '../../integration/setup/msw-test-server'; ``` -------------------------------------------------------------------------------- /src/utils/version.ts: -------------------------------------------------------------------------------- ```typescript import { readFileSync } from 'fs'; import { join } from 'path'; /** * Get the project version from package.json * This ensures we have a single source of truth for versioning */ function getProjectVersion(): string { try { const packageJsonPath = join(__dirname, '../../package.json'); const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); return packageJson.version || '0.0.0'; } catch (error) { console.error('Failed to read version from package.json:', error); return '0.0.0'; } } export const PROJECT_VERSION = getProjectVersion(); ``` -------------------------------------------------------------------------------- /docker-compose.test-n8n.yml: -------------------------------------------------------------------------------- ```yaml # docker-compose.test-n8n.yml - Simple test setup for n8n integration # Run n8n in Docker, n8n-mcp locally for faster testing version: '3.8' services: n8n: image: n8nio/n8n:latest container_name: n8n-test ports: - "5678:5678" environment: - N8N_BASIC_AUTH_ACTIVE=false - N8N_HOST=localhost - N8N_PORT=5678 - N8N_PROTOCOL=http - NODE_ENV=development - N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true volumes: - n8n_test_data:/home/node/.n8n network_mode: "host" # Use host network for easy local testing volumes: n8n_test_data: ``` -------------------------------------------------------------------------------- /tests/test-node-list.js: -------------------------------------------------------------------------------- ```javascript #!/usr/bin/env node const { NodeSourceExtractor } = require('../dist/utils/node-source-extractor'); async function testNodeList() { console.log('Testing node list...\n'); const extractor = new NodeSourceExtractor(); try { const nodes = await extractor.listAvailableNodes(); console.log(`Total nodes found: ${nodes.length}`); // Show first 5 nodes console.log('\nFirst 5 nodes:'); nodes.slice(0, 5).forEach((node, index) => { console.log(`${index + 1}. Node:`, JSON.stringify(node, null, 2)); }); } catch (error) { console.error('Error:', error); } } testNodeList(); ``` -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- ```yaml # Jekyll configuration for GitHub Pages # This is only used for serving benchmark results # Only process benchmark-related files include: - index.html - benchmarks/ # Exclude everything else to prevent Liquid syntax errors exclude: - "*.md" - "*.json" - "*.ts" - "*.js" - "*.yml" - src/ - tests/ - docs/ - scripts/ - dist/ - node_modules/ - package.json - package-lock.json - tsconfig.json - README.md - CHANGELOG.md - LICENSE - Dockerfile* - docker-compose* - .github/ - .vscode/ - .claude/ - deploy/ - examples/ - data/ # Disable Jekyll processing for files we don't want processed plugins: [] # Use simple theme theme: null ``` -------------------------------------------------------------------------------- /vitest.config.benchmark.ts: -------------------------------------------------------------------------------- ```typescript import { defineConfig } from 'vitest/config'; import path from 'path'; export default defineConfig({ test: { globals: true, environment: 'node', include: ['tests/benchmarks/**/*.bench.ts'], benchmark: { // Benchmark specific options include: ['tests/benchmarks/**/*.bench.ts'], reporters: ['default'], }, setupFiles: [], pool: 'forks', poolOptions: { forks: { singleFork: true, }, }, // Increase timeout for benchmarks testTimeout: 120000, hookTimeout: 120000, }, resolve: { alias: { '@': path.resolve(__dirname, './src'), '@tests': path.resolve(__dirname, './tests'), }, }, }); ``` -------------------------------------------------------------------------------- /package.runtime.json: -------------------------------------------------------------------------------- ```json { "name": "n8n-mcp-runtime", "version": "2.19.3", "description": "n8n MCP Server Runtime Dependencies Only", "private": true, "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", "require": "./dist/index.js", "import": "./dist/index.js" } }, "dependencies": { "@modelcontextprotocol/sdk": "^1.13.2", "@supabase/supabase-js": "^2.57.4", "express": "^5.1.0", "express-rate-limit": "^7.1.5", "dotenv": "^16.5.0", "lru-cache": "^11.2.1", "sql.js": "^1.13.0", "uuid": "^10.0.0", "axios": "^1.7.7" }, "engines": { "node": ">=16.0.0" }, "optionalDependencies": { "better-sqlite3": "^11.10.0" } } ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/types.ts: -------------------------------------------------------------------------------- ```typescript export interface ToolDocumentation { name: string; category: string; essentials: { description: string; keyParameters: string[]; example: string; performance: string; tips: string[]; }; full: { description: string; parameters: Record<string, { type: string; description: string; required?: boolean; default?: any; examples?: string[]; enum?: string[]; }>; returns: string; examples: string[]; useCases: string[]; performance: string; errorHandling?: string; // Optional: Documentation on error handling and debugging bestPractices: string[]; pitfalls: string[]; modeComparison?: string; // Optional: Comparison of different modes for tools with multiple modes relatedTools: string[]; }; } ``` -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- ```typescript // Export n8n node type definitions and utilities export * from './node-types'; export interface MCPServerConfig { port: number; host: string; authToken?: string; } export interface ToolDefinition { name: string; description: string; inputSchema: { type: string; properties: Record<string, any>; required?: string[]; additionalProperties?: boolean | Record<string, any>; }; outputSchema?: { type: string; properties: Record<string, any>; required?: string[]; additionalProperties?: boolean | Record<string, any>; }; } export interface ResourceDefinition { uri: string; name: string; description?: string; mimeType?: string; } export interface PromptDefinition { name: string; description?: string; arguments?: Array<{ name: string; description?: string; required?: boolean; }>; } ``` -------------------------------------------------------------------------------- /vitest.config.integration.ts: -------------------------------------------------------------------------------- ```typescript import { defineConfig, mergeConfig } from 'vitest/config'; import baseConfig from './vitest.config'; export default mergeConfig( baseConfig, defineConfig({ test: { // Include global setup, but NOT integration-setup.ts for n8n-api tests // (they need real network requests, not MSW mocks) setupFiles: ['./tests/setup/global-setup.ts'], // Only include integration tests include: ['tests/integration/**/*.test.ts'], // Integration tests might need more time testTimeout: 30000, // Specific pool options for integration tests poolOptions: { threads: { // Run integration tests sequentially by default singleThread: true, maxThreads: 1 } }, // Disable coverage for integration tests or set lower thresholds coverage: { enabled: false } } }) ); ``` -------------------------------------------------------------------------------- /ATTRIBUTION.md: -------------------------------------------------------------------------------- ```markdown # Attribution ## Using n8n-MCP in Your Project? While not legally required, we'd love it if you included attribution! Here are some easy ways: ### In Your README ``` Built with [n8n-MCP](https://github.com/czlonkowski/n8n-mcp) by Romuald Czlonkowski @ [www.aiadvisors.pl/en](https://www.aiadvisors.pl/en) ``` ### In Your Documentation ``` This project uses n8n-MCP (https://github.com/czlonkowski/n8n-mcp) for n8n node documentation access. Created by Romuald Czlonkowski @ www.aiadvisors.pl/en ``` ### In Code Comments ```javascript // Powered by n8n-MCP - https://github.com/czlonkowski/n8n-mcp // Created by Romuald Czlonkowski @ www.aiadvisors.pl/en ``` ## Why Attribution Matters Attribution helps: - Other developers discover this tool - Build a stronger n8n community - Me understand how the tool is being used - You get support and updates Thank you for using n8n-MCP! 🙏 ``` -------------------------------------------------------------------------------- /types/mcp.d.ts: -------------------------------------------------------------------------------- ```typescript // Type declarations for MCP SDK responses declare module '@modelcontextprotocol/sdk/client/index.js' { export * from '@modelcontextprotocol/sdk/client/index'; export interface ToolsListResponse { tools: Array<{ name: string; description?: string; inputSchema?: any; }>; } export interface CallToolResponse { content: Array<{ type: string; text?: string; }>; } } declare module '@modelcontextprotocol/sdk/server/index.js' { export * from '@modelcontextprotocol/sdk/server/index'; } declare module '@modelcontextprotocol/sdk/server/stdio.js' { export * from '@modelcontextprotocol/sdk/server/stdio'; } declare module '@modelcontextprotocol/sdk/client/stdio.js' { export * from '@modelcontextprotocol/sdk/client/stdio'; } declare module '@modelcontextprotocol/sdk/types.js' { export * from '@modelcontextprotocol/sdk/types'; } ``` -------------------------------------------------------------------------------- /scripts/update-readme-version.js: -------------------------------------------------------------------------------- ```javascript #!/usr/bin/env node const fs = require('fs'); const path = require('path'); // Read package.json const packageJsonPath = path.join(__dirname, '..', 'package.json'); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const version = packageJson.version; // Read README.md const readmePath = path.join(__dirname, '..', 'README.md'); let readmeContent = fs.readFileSync(readmePath, 'utf8'); // Update the version badge on line 5 // The pattern matches: [] const versionBadgeRegex = /(\[!\[Version\]\(https:\/\/img\.shields\.io\/badge\/version-)[^-]+(-.+?\)\])/; const newVersionBadge = `$1${version}$2`; readmeContent = readmeContent.replace(versionBadgeRegex, newVersionBadge); // Write back to README.md fs.writeFileSync(readmePath, readmeContent); console.log(`✅ Updated README.md version badge to v${version}`); ``` -------------------------------------------------------------------------------- /tests/integration/n8n-api/test-connection.ts: -------------------------------------------------------------------------------- ```typescript /** * Quick test script to verify n8n API connection */ import { getN8nCredentials } from './utils/credentials'; import { getTestN8nClient } from './utils/n8n-client'; async function testConnection() { try { console.log('Loading credentials...'); const creds = getN8nCredentials(); console.log('Credentials loaded:', { url: creds.url, hasApiKey: !!creds.apiKey, apiKeyLength: creds.apiKey?.length }); console.log('\nCreating n8n client...'); const client = getTestN8nClient(); console.log('Client created successfully'); console.log('\nTesting health check...'); const health = await client.healthCheck(); console.log('Health check result:', health); console.log('\n✅ Connection test passed!'); } catch (error) { console.error('❌ Connection test failed:'); console.error(error); process.exit(1); } } testConnection(); ``` -------------------------------------------------------------------------------- /scripts/deploy-http.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Simple deployment script for n8n-MCP HTTP server # For private, single-user deployments only set -e echo "n8n-MCP HTTP Deployment Script" echo "==============================" echo "" # Check if .env exists if [ ! -f .env ]; then echo "Creating .env file..." cp .env.example .env echo "" echo "⚠️ Please edit .env file and set:" echo " - AUTH_TOKEN (generate with: openssl rand -base64 32)" echo " - MCP_MODE=http" echo " - PORT (default 3000)" echo "" exit 1 fi # Check if AUTH_TOKEN is set if ! grep -q "AUTH_TOKEN=.*[a-zA-Z0-9]" .env; then echo "ERROR: AUTH_TOKEN not set in .env file" echo "Generate one with: openssl rand -base64 32" exit 1 fi # Build and start echo "Building project..." npm run build echo "" echo "Starting HTTP server..." echo "Use Ctrl+C to stop" echo "" # Start with production settings NODE_ENV=production npm run start:http ``` -------------------------------------------------------------------------------- /scripts/test-telemetry-simple.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env npx tsx /** * Simple test to verify telemetry works */ import { createClient } from '@supabase/supabase-js'; import dotenv from 'dotenv'; dotenv.config(); async function testSimple() { const supabaseUrl = process.env.SUPABASE_URL!; const supabaseAnonKey = process.env.SUPABASE_ANON_KEY!; console.log('🧪 Simple Telemetry Test\n'); const supabase = createClient(supabaseUrl, supabaseAnonKey, { auth: { persistSession: false, autoRefreshToken: false, } }); // Simple insert const testData = { user_id: 'simple-test-' + Date.now(), event: 'test_event', properties: { test: true } }; console.log('Inserting:', testData); const { data, error } = await supabase .from('telemetry_events') .insert([testData]) .select(); if (error) { console.error('❌ Failed:', error); } else { console.log('✅ Success! Inserted:', data); } } testSimple().catch(console.error); ``` -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- ```yaml codecov: require_ci_to_pass: yes coverage: precision: 2 round: down range: "70...100" status: project: default: target: 80% threshold: 1% base: auto if_not_found: success if_ci_failed: error informational: false only_pulls: false patch: default: target: 80% threshold: 1% base: auto if_not_found: success if_ci_failed: error informational: true only_pulls: false parsers: gcov: branch_detection: conditional: yes loop: yes method: no macro: no comment: layout: "reach,diff,flags,files,footer" behavior: default require_changes: false require_base: false require_head: true ignore: - "node_modules/**/*" - "dist/**/*" - "tests/**/*" - "scripts/**/*" - "**/*.test.ts" - "**/*.spec.ts" - "src/mcp/index.ts" - "src/http-server.ts" - "src/http-server-single-session.ts" ``` -------------------------------------------------------------------------------- /monitor_fetch.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash echo "Monitoring template fetch progress..." echo "==================================" while true; do # Check if process is still running if ! pgrep -f "fetch-templates" > /dev/null; then echo "Fetch process completed!" break fi # Get database size DB_SIZE=$(ls -lh data/nodes.db 2>/dev/null | awk '{print $5}') # Get template count TEMPLATE_COUNT=$(sqlite3 data/nodes.db "SELECT COUNT(*) FROM templates" 2>/dev/null || echo "0") # Get last log entry LAST_LOG=$(tail -n 1 fetch_log.txt 2>/dev/null | grep "Fetching template details" | tail -1) # Display status echo -ne "\rDB Size: $DB_SIZE | Templates: $TEMPLATE_COUNT | $LAST_LOG" sleep 5 done echo "" echo "Final statistics:" echo "-----------------" ls -lh data/nodes.db sqlite3 data/nodes.db "SELECT COUNT(*) as count, printf('%.1f MB', SUM(LENGTH(workflow_json_compressed))/1024.0/1024.0) as compressed_size FROM templates" ``` -------------------------------------------------------------------------------- /src/mcp/tool-docs/workflow_management/index.ts: -------------------------------------------------------------------------------- ```typescript export { n8nCreateWorkflowDoc } from './n8n-create-workflow'; export { n8nGetWorkflowDoc } from './n8n-get-workflow'; export { n8nGetWorkflowDetailsDoc } from './n8n-get-workflow-details'; export { n8nGetWorkflowStructureDoc } from './n8n-get-workflow-structure'; export { n8nGetWorkflowMinimalDoc } from './n8n-get-workflow-minimal'; export { n8nUpdateFullWorkflowDoc } from './n8n-update-full-workflow'; export { n8nUpdatePartialWorkflowDoc } from './n8n-update-partial-workflow'; export { n8nDeleteWorkflowDoc } from './n8n-delete-workflow'; export { n8nListWorkflowsDoc } from './n8n-list-workflows'; export { n8nValidateWorkflowDoc } from './n8n-validate-workflow'; export { n8nAutofixWorkflowDoc } from './n8n-autofix-workflow'; export { n8nTriggerWebhookWorkflowDoc } from './n8n-trigger-webhook-workflow'; export { n8nGetExecutionDoc } from './n8n-get-execution'; export { n8nListExecutionsDoc } from './n8n-list-executions'; export { n8nDeleteExecutionDoc } from './n8n-delete-execution'; ``` -------------------------------------------------------------------------------- /tests/test-package-info.js: -------------------------------------------------------------------------------- ```javascript #!/usr/bin/env node const { NodeSourceExtractor } = require('../dist/utils/node-source-extractor'); async function testPackageInfo() { console.log('🧪 Testing Package Info Extraction\n'); const extractor = new NodeSourceExtractor(); const testNodes = [ 'n8n-nodes-base.Slack', 'n8n-nodes-base.HttpRequest', 'n8n-nodes-base.Function' ]; for (const nodeType of testNodes) { console.log(`\n📦 Testing ${nodeType}:`); try { const result = await extractor.extractNodeSource(nodeType); console.log(` - Source Code: ${result.sourceCode ? '✅' : '❌'} (${result.sourceCode?.length || 0} bytes)`); console.log(` - Credential Code: ${result.credentialCode ? '✅' : '❌'} (${result.credentialCode?.length || 0} bytes)`); console.log(` - Package Name: ${result.packageInfo?.name || '❌ undefined'}`); console.log(` - Package Version: ${result.packageInfo?.version || '❌ undefined'}`); } catch (error) { console.log(` ❌ Error: ${error.message}`); } } } testPackageInfo().catch(console.error); ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "types": ["node", "vitest/globals", "./types/test-env"], "outDir": "./dist", "rootDir": "./", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true, "removeComments": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, "noUnusedLocals": false, "noUnusedParameters": false, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", "allowJs": true, "baseUrl": ".", "paths": { "@/*": ["src/*"], "@tests/*": ["tests/*"] } }, "include": ["src/**/*", "tests/**/*", "vitest.config.ts", "types/**/*"], "exclude": ["node_modules", "dist"] } ``` -------------------------------------------------------------------------------- /scripts/generate-benchmark-stub.js: -------------------------------------------------------------------------------- ```javascript #!/usr/bin/env node /** * Generates a stub benchmark-results.json file when benchmarks fail to produce output. * This ensures the CI pipeline doesn't fail due to missing files. */ const fs = require('fs'); const path = require('path'); const stubResults = { timestamp: new Date().toISOString(), files: [ { filepath: 'tests/benchmarks/stub.bench.ts', groups: [ { name: 'Stub Benchmarks', benchmarks: [ { name: 'stub-benchmark', result: { mean: 0.001, min: 0.001, max: 0.001, hz: 1000, p75: 0.001, p99: 0.001, p995: 0.001, p999: 0.001, rme: 0, samples: 1 } } ] } ] } ] }; const outputPath = path.join(process.cwd(), 'benchmark-results.json'); fs.writeFileSync(outputPath, JSON.stringify(stubResults, null, 2)); console.log(`Generated stub benchmark results at ${outputPath}`); ``` -------------------------------------------------------------------------------- /tests/mocks/n8n-api/data/credentials.ts: -------------------------------------------------------------------------------- ```typescript /** * Mock credential data for MSW handlers */ export interface MockCredential { id: string; name: string; type: string; data?: Record<string, any>; // Usually encrypted in real n8n createdAt: string; updatedAt: string; } export const mockCredentials: MockCredential[] = [ { id: 'cred_1', name: 'Slack Account', type: 'slackApi', createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' }, { id: 'cred_2', name: 'HTTP Header Auth', type: 'httpHeaderAuth', createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' }, { id: 'cred_3', name: 'OpenAI API', type: 'openAiApi', createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' } ]; /** * Factory for creating mock credentials */ export const credentialFactory = { create: (type: string, name?: string): MockCredential => ({ id: `cred_${Date.now()}`, name: name || `${type} Credential`, type, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }) }; ``` -------------------------------------------------------------------------------- /docker-compose.buildkit.yml: -------------------------------------------------------------------------------- ```yaml # Docker Compose file with BuildKit optimizations for faster builds # This now builds without n8n dependencies for ultra-fast builds version: '3.8' services: n8n-mcp: build: context: . dockerfile: Dockerfile # Enable BuildKit x-bake: cache-from: - type=gha - type=local,src=/tmp/.buildx-cache cache-to: - type=gha,mode=max - type=local,dest=/tmp/.buildx-cache-new,mode=max args: BUILDKIT_INLINE_CACHE: 1 image: n8n-mcp:latest container_name: n8n-mcp ports: - "3000:3000" environment: - MCP_MODE=${MCP_MODE:-http} - AUTH_TOKEN=${AUTH_TOKEN} - NODE_ENV=${NODE_ENV:-production} - LOG_LEVEL=${LOG_LEVEL:-info} - PORT=3000 volumes: # Mount data directory for persistence - ./data:/app/data restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 5s # Use external network if needed networks: default: name: n8n-mcp-network ``` -------------------------------------------------------------------------------- /scripts/test-fuzzy-simple.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env node import { N8NDocumentationMCPServer } from '../src/mcp/server'; async function testSimple() { const server = new N8NDocumentationMCPServer(); await new Promise(resolve => setTimeout(resolve, 1000)); // Just test one query const result = await server.executeTool('search_nodes', { query: 'slak', mode: 'FUZZY', limit: 5 }); console.log('Query: "slak" (FUZZY mode)'); console.log(`Results: ${result.results.length}`); if (result.results.length === 0) { // Let's check with a lower threshold const serverAny = server as any; const slackNode = { node_type: 'nodes-base.slack', display_name: 'Slack', description: 'Consume Slack API' }; const score = serverAny.calculateFuzzyScore(slackNode, 'slak'); console.log(`\nSlack node score for "slak": ${score}`); console.log('Current threshold: 400'); console.log('Should it match?', score >= 400 ? 'YES' : 'NO'); } else { result.results.forEach((r: any, i: number) => { console.log(`${i + 1}. ${r.displayName}`); }); } } testSimple().catch(console.error); ``` -------------------------------------------------------------------------------- /src/n8n/MCPApi.credentials.ts: -------------------------------------------------------------------------------- ```typescript import { ICredentialType, INodeProperties, } from 'n8n-workflow'; export class MCPApi implements ICredentialType { name = 'mcpApi'; displayName = 'MCP API'; documentationUrl = 'mcp'; properties: INodeProperties[] = [ { displayName: 'Server URL', name: 'serverUrl', type: 'string', default: 'http://localhost:3000', placeholder: 'http://localhost:3000', description: 'The URL of the MCP server', }, { displayName: 'Authentication Token', name: 'authToken', type: 'string', typeOptions: { password: true, }, default: '', description: 'Authentication token for the MCP server (if required)', }, { displayName: 'Connection Type', name: 'connectionType', type: 'options', options: [ { name: 'HTTP', value: 'http', }, { name: 'WebSocket', value: 'websocket', }, { name: 'STDIO', value: 'stdio', }, ], default: 'http', description: 'How to connect to the MCP server', }, ]; } ``` -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- ```typescript /** * n8n-MCP - Model Context Protocol Server for n8n * Copyright (c) 2024 AiAdvisors Romuald Czlonkowski * Licensed under the Sustainable Use License v1.0 */ // Engine exports for service integration export { N8NMCPEngine, EngineHealth, EngineOptions } from './mcp-engine'; export { SingleSessionHTTPServer } from './http-server-single-session'; export { ConsoleManager } from './utils/console-manager'; export { N8NDocumentationMCPServer } from './mcp/server'; // Type exports for multi-tenant and library usage export type { InstanceContext } from './types/instance-context'; export { validateInstanceContext, isInstanceContext } from './types/instance-context'; // Session restoration types (v2.19.0) export type { SessionRestoreHook, SessionRestorationOptions, SessionState } from './types/session-restoration'; // Re-export MCP SDK types for convenience export type { Tool, CallToolResult, ListToolsResult } from '@modelcontextprotocol/sdk/types.js'; // Default export for convenience import N8NMCPEngine from './mcp-engine'; export default N8NMCPEngine; // Legacy CLI functionality - moved to ./mcp/index.ts // This file now serves as the main entry point for library usage ``` -------------------------------------------------------------------------------- /scripts/test-docker-config.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Script to run Docker config tests # Usage: ./scripts/test-docker-config.sh [unit|integration|all] set -e MODE=${1:-all} echo "Running Docker config tests in mode: $MODE" case $MODE in unit) echo "Running unit tests..." npm test -- tests/unit/docker/ ;; integration) echo "Running integration tests (requires Docker)..." RUN_DOCKER_TESTS=true npm run test:integration -- tests/integration/docker/ ;; all) echo "Running all Docker config tests..." npm test -- tests/unit/docker/ if command -v docker &> /dev/null; then echo "Docker found, running integration tests..." RUN_DOCKER_TESTS=true npm run test:integration -- tests/integration/docker/ else echo "Docker not found, skipping integration tests" fi ;; coverage) echo "Running Docker config tests with coverage..." npm run test:coverage -- tests/unit/docker/ ;; security) echo "Running security-focused tests..." npm test -- tests/unit/docker/config-security.test.ts tests/unit/docker/parse-config.test.ts ;; *) echo "Usage: $0 [unit|integration|all|coverage|security]" exit 1 ;; esac echo "Docker config tests completed!" ``` -------------------------------------------------------------------------------- /src/utils/simple-cache.ts: -------------------------------------------------------------------------------- ```typescript /** * Simple in-memory cache with TTL support * No external dependencies needed */ export class SimpleCache { private cache = new Map<string, { data: any; expires: number }>(); private cleanupTimer: NodeJS.Timeout | null = null; constructor() { // Clean up expired entries every minute this.cleanupTimer = setInterval(() => { const now = Date.now(); for (const [key, item] of this.cache.entries()) { if (item.expires < now) this.cache.delete(key); } }, 60000); } get(key: string): any { const item = this.cache.get(key); if (!item || item.expires < Date.now()) { this.cache.delete(key); return null; } return item.data; } set(key: string, data: any, ttlSeconds: number = 300): void { this.cache.set(key, { data, expires: Date.now() + (ttlSeconds * 1000) }); } clear(): void { this.cache.clear(); } /** * Clean up the cache and stop the cleanup timer * Essential for preventing memory leaks in long-running servers */ destroy(): void { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = null; } this.cache.clear(); } } ``` -------------------------------------------------------------------------------- /docs/CODEX_SETUP.md: -------------------------------------------------------------------------------- ```markdown # Codex Setup Connect n8n-MCP to Codex for enhanced n8n workflow development. ## Update your Codex configuration Go to your Codex settings at `~/.codex/config.toml` and add the following configuration: ### Basic configuration (documentation tools only): ```toml [mcp_servers.n8n] command = "npx" args = ["n8n-mcp"] env = { "MCP_MODE" = "stdio", "LOG_LEVEL" = "error", "DISABLE_CONSOLE_OUTPUT" = "true" } ``` ### Full configuration (with n8n management tools): ```toml [mcp_servers.n8n] command = "npx" args = ["n8n-mcp"] env = { "MCP_MODE" = "stdio", "LOG_LEVEL" = "error", "DISABLE_CONSOLE_OUTPUT" = "true", "N8N_API_URL" = "https://your-n8n-instance.com", "N8N_API_KEY" = "your-api-key" } ``` Make sure to replace `https://your-n8n-instance.com` with your actual n8n URL and `your-api-key` with your n8n API key. ## Managing Your MCP Server Enter the Codex CLI and use the `/mcp` command to see server status and available tools.  ## Project Instructions For optimal results, create a `AGENTS.md` file in your project root with the instructions same with [main README's Claude Project Setup section](../README.md#-claude-project-setup). ``` -------------------------------------------------------------------------------- /tests/integration/n8n-api/scripts/cleanup-orphans.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env tsx /** * Cleanup Orphaned Test Resources * * Standalone script to clean up orphaned workflows and executions * from failed test runs. Run this periodically in CI or manually * to maintain a clean test environment. * * Usage: * npm run test:cleanup:orphans * tsx tests/integration/n8n-api/scripts/cleanup-orphans.ts */ import { cleanupAllTestResources } from '../utils/cleanup-helpers'; import { getN8nCredentials, validateCredentials } from '../utils/credentials'; async function main() { console.log('Starting cleanup of orphaned test resources...\n'); try { // Validate credentials const creds = getN8nCredentials(); validateCredentials(creds); console.log(`n8n Instance: ${creds.url}`); console.log(`Cleanup Tag: ${creds.cleanup.tag}`); console.log(`Cleanup Prefix: ${creds.cleanup.namePrefix}\n`); // Run cleanup const result = await cleanupAllTestResources(); console.log('\n✅ Cleanup complete!'); console.log(` Workflows deleted: ${result.workflows}`); console.log(` Executions deleted: ${result.executions}`); process.exit(0); } catch (error) { console.error('\n❌ Cleanup failed:', error); process.exit(1); } } main(); ``` -------------------------------------------------------------------------------- /scripts/test-telemetry-direct.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env npx tsx /** * Direct telemetry test with hardcoded credentials */ import { createClient } from '@supabase/supabase-js'; const TELEMETRY_BACKEND = { URL: 'https://ydyufsohxdfpopqbubwk.supabase.co', ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkeXVmc29oeGRmcG9wcWJ1YndrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mzc2MzAxMDgsImV4cCI6MjA1MzIwNjEwOH0.LsUTx9OsNtnqg-jxXaJPc84aBHVDehHiMaFoF2Ir8s0' }; async function testDirect() { console.log('🧪 Direct Telemetry Test\n'); const supabase = createClient(TELEMETRY_BACKEND.URL, TELEMETRY_BACKEND.ANON_KEY, { auth: { persistSession: false, autoRefreshToken: false, } }); const testEvent = { user_id: 'direct-test-' + Date.now(), event: 'direct_test', properties: { source: 'test-telemetry-direct.ts', timestamp: new Date().toISOString() } }; console.log('Sending event:', testEvent); const { data, error } = await supabase .from('telemetry_events') .insert([testEvent]); if (error) { console.error('❌ Failed:', error); } else { console.log('✅ Success! Event sent directly to Supabase'); console.log('Response:', data); } } testDirect().catch(console.error); ``` -------------------------------------------------------------------------------- /scripts/test-docker.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # scripts/test-docker.sh echo "🧪 Testing n8n-MCP Docker Deployment" # Test 1: Build simple image echo "1. Building simple Docker image..." docker build -t n8n-mcp:test . # Test 2: Test stdio mode echo "2. Testing stdio mode..." echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | \ docker run --rm -i -e MCP_MODE=stdio n8n-mcp:test # Test 3: Test HTTP mode echo "3. Testing HTTP mode..." docker run -d --name test-http \ -e MCP_MODE=http \ -e AUTH_TOKEN=test-token \ -p 3001:3000 \ n8n-mcp:test sleep 5 # Check health curl -f http://localhost:3001/health || echo "Health check failed" # Test auth curl -H "Authorization: Bearer test-token" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \ http://localhost:3001/mcp docker stop test-http && docker rm test-http # Test 4: Volume persistence echo "4. Testing volume persistence..." docker volume create test-data docker run -d --name test-persist \ -v test-data:/app/data \ -e MCP_MODE=http \ -e AUTH_TOKEN=test \ -p 3002:3000 \ n8n-mcp:test sleep 10 docker exec test-persist ls -la /app/data/nodes.db docker stop test-persist && docker rm test-persist docker volume rm test-data echo "✅ Docker tests completed!" ``` -------------------------------------------------------------------------------- /src/errors/validation-service-error.ts: -------------------------------------------------------------------------------- ```typescript /** * Custom error class for validation service failures */ export class ValidationServiceError extends Error { constructor( message: string, public readonly nodeType?: string, public readonly property?: string, public readonly cause?: Error ) { super(message); this.name = 'ValidationServiceError'; // Maintains proper stack trace for where our error was thrown (only available on V8) if (Error.captureStackTrace) { Error.captureStackTrace(this, ValidationServiceError); } } /** * Create error for JSON parsing failure */ static jsonParseError(nodeType: string, cause: Error): ValidationServiceError { return new ValidationServiceError( `Failed to parse JSON data for node ${nodeType}`, nodeType, undefined, cause ); } /** * Create error for node not found */ static nodeNotFound(nodeType: string): ValidationServiceError { return new ValidationServiceError( `Node type ${nodeType} not found in repository`, nodeType ); } /** * Create error for critical data extraction failure */ static dataExtractionError(nodeType: string, dataType: string, cause?: Error): ValidationServiceError { return new ValidationServiceError( `Failed to extract ${dataType} for node ${nodeType}`, nodeType, dataType, cause ); } } ``` -------------------------------------------------------------------------------- /scripts/build-optimized.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Optimized Docker build script - no n8n dependencies! set -e # Enable BuildKit export DOCKER_BUILDKIT=1 export COMPOSE_DOCKER_CLI_BUILD=1 echo "🚀 Building n8n-mcp (runtime-only, no n8n deps)..." echo "💡 This build assumes database is pre-built" # Check if nodes.db exists if [ ! -f "data/nodes.db" ]; then echo "⚠️ Warning: data/nodes.db not found!" echo " Run 'npm run rebuild' first to create the database" exit 1 fi # Build with BuildKit echo "📦 Building Docker image..." docker build \ --progress=plain \ --cache-from type=gha \ --cache-from type=registry,ref=ghcr.io/czlonkowski/n8n-mcp:buildcache \ --build-arg BUILDKIT_INLINE_CACHE=1 \ -t "n8n-mcp:latest" \ . # Show image size echo "" echo "📊 Image size:" docker images n8n-mcp:latest --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" # Test the build echo "" echo "🧪 Testing build..." docker run --rm n8n-mcp:latest node -e "console.log('Build OK - Runtime dependencies only!')" # Estimate size savings echo "" echo "💰 Size comparison:" echo " Old approach (with n8n deps): ~1.5GB" echo " New approach (runtime only): ~280MB" echo " Savings: ~82% smaller!" echo "" echo "✅ Build complete!" echo "" echo "🎯 Next steps:" echo " - Use 'docker run -p 3000:3000 -e AUTH_TOKEN=your-token n8n-mcp:latest' to run" echo " - Use 'docker-compose up' for production deployment" echo " - Remember to rebuild database locally before pushing!" ``` -------------------------------------------------------------------------------- /scripts/test-http-search.ts: -------------------------------------------------------------------------------- ```typescript #\!/usr/bin/env node import { N8NDocumentationMCPServer } from '../src/mcp/server'; async function testHttpSearch() { const server = new N8NDocumentationMCPServer(); await new Promise(resolve => setTimeout(resolve, 1000)); console.log('Testing search for "http"...\n'); const result = await server.executeTool('search_nodes', { query: 'http', limit: 50 // Get more results to see where HTTP Request is }); console.log(`Total results: ${result.results.length}\n`); // Find HTTP Request node in results const httpRequestIndex = result.results.findIndex((r: any) => r.nodeType === 'nodes-base.httpRequest' ); if (httpRequestIndex === -1) { console.log('❌ HTTP Request node NOT FOUND in results\!'); } else { console.log(`✅ HTTP Request found at position ${httpRequestIndex + 1}`); } console.log('\nTop 10 results:'); result.results.slice(0, 10).forEach((r: any, i: number) => { console.log(`${i + 1}. ${r.nodeType} - ${r.displayName}`); }); // Also check LIKE search directly console.log('\n\nTesting LIKE search fallback:'); const serverAny = server as any; const likeResult = await serverAny.searchNodesLIKE('http', 20); console.log(`LIKE search found ${likeResult.results.length} results`); console.log('Top 5 LIKE results:'); likeResult.results.slice(0, 5).forEach((r: any, i: number) => { console.log(`${i + 1}. ${r.nodeType} - ${r.displayName}`); }); } testHttpSearch().catch(console.error); ``` -------------------------------------------------------------------------------- /docker-compose.extract.yml: -------------------------------------------------------------------------------- ```yaml version: '3.8' services: # Latest n8n container for node extraction n8n-latest: image: n8nio/n8n:latest container_name: n8n-latest-extractor environment: - N8N_BASIC_AUTH_ACTIVE=false - N8N_PORT=5678 - N8N_ENCRYPTION_KEY=dummy-key-for-extraction volumes: # Mount n8n's node_modules for extraction - n8n_modules:/usr/local/lib/node_modules/n8n/node_modules # Provide writable directory for n8n config - n8n_config:/home/node/.n8n # We don't need n8n to stay running, just to install modules entrypoint: ["sh", "-c", "sleep 300"] healthcheck: test: ["CMD-SHELL", "ls /usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base > /dev/null 2>&1"] interval: 5s timeout: 30s retries: 20 # Extractor service that will read from the mounted volumes node-extractor: image: node:22-alpine container_name: n8n-node-extractor working_dir: /app depends_on: n8n-latest: condition: service_healthy volumes: # Mount the n8n modules from the n8n container - n8n_modules:/n8n-modules:ro - n8n_custom:/n8n-custom:ro # Mount our project files - ./:/app environment: - NODE_ENV=development - NODE_DB_PATH=/app/data/nodes-fresh.db - N8N_MODULES_PATH=/n8n-modules - N8N_CUSTOM_PATH=/n8n-custom command: /bin/sh -c "apk add --no-cache sqlite && node /app/scripts/extract-from-docker.js" volumes: n8n_modules: n8n_custom: n8n_config: ``` -------------------------------------------------------------------------------- /scripts/test-workflow-insert.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env npx tsx /** * Test direct workflow insert to Supabase */ import { createClient } from '@supabase/supabase-js'; const TELEMETRY_BACKEND = { URL: 'https://ydyufsohxdfpopqbubwk.supabase.co', ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkeXVmc29oeGRmcG9wcWJ1YndrIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTg3OTYyMDAsImV4cCI6MjA3NDM3MjIwMH0.xESphg6h5ozaDsm4Vla3QnDJGc6Nc_cpfoqTHRynkCk' }; async function testWorkflowInsert() { const supabase = createClient(TELEMETRY_BACKEND.URL, TELEMETRY_BACKEND.ANON_KEY, { auth: { persistSession: false, autoRefreshToken: false, } }); const testWorkflow = { user_id: 'direct-test-' + Date.now(), workflow_hash: 'hash-direct-' + Date.now(), node_count: 2, node_types: ['webhook', 'http'], has_trigger: true, has_webhook: true, complexity: 'simple' as const, sanitized_workflow: { nodes: [ { id: '1', type: 'webhook', parameters: {} }, { id: '2', type: 'http', parameters: {} } ], connections: {} } }; console.log('Attempting direct insert to telemetry_workflows...'); console.log('Data:', JSON.stringify(testWorkflow, null, 2)); const { data, error } = await supabase .from('telemetry_workflows') .insert([testWorkflow]); if (error) { console.error('\n❌ Error:', error); } else { console.log('\n✅ Success! Workflow inserted'); if (data) { console.log('Response:', data); } } } testWorkflowInsert().catch(console.error); ``` -------------------------------------------------------------------------------- /.github/ABOUT.md: -------------------------------------------------------------------------------- ```markdown # About n8n-MCP **n8n-MCP** is a Model Context Protocol (MCP) server that gives AI assistants like Claude deep understanding of n8n's 525+ workflow automation nodes. ## 🎯 What it does - Provides AI assistants with instant access to n8n node documentation, properties, and examples - Reduces workflow creation time from 45 minutes to 3 minutes (as tested by Claude) - Eliminates guesswork with accurate node configurations and validation - Enables AI to build production-ready n8n workflows on the first try ## 🚀 Key Features - **Smart Search** - Find the right nodes instantly - **Essential Properties** - Get only what matters (10-20 properties instead of 200+) - **Task Templates** - Pre-configured settings for common automations - **Real-time Validation** - Catch errors before deployment - **Universal Compatibility** - Works with any Node.js version ## 📊 Impact > "Before MCP, I was translating. Now I'm composing." - Claude - **6 errors → 0 errors** in workflow creation - **45 minutes → 3 minutes** development time - **100% node coverage** with 90% documentation - **263 AI-capable nodes** fully documented ## 🔧 Use Cases Perfect for: - AI assistants building n8n workflows - Developers learning n8n - Teams using AI for automation - Anyone tired of trial-and-error workflow building ## 🏃 Get Started ```bash # Quick start with Docker docker run -it ghcr.io/czlonkowski/n8n-mcp:latest ``` See the [README](../README.md) for full setup instructions. --- **Built with ❤️ for the n8n community** | Making AI + n8n workflow creation delightful ``` -------------------------------------------------------------------------------- /tests/integration/docker/test-helpers.ts: -------------------------------------------------------------------------------- ```typescript import { promisify } from 'util'; import { exec as execCallback } from 'child_process'; export const exec = promisify(execCallback); /** * Wait for a container to be healthy by checking the health endpoint */ export async function waitForHealthy(containerName: string, timeout = 10000): Promise<boolean> { const startTime = Date.now(); while (Date.now() - startTime < timeout) { try { const { stdout } = await exec( `docker exec ${containerName} curl -s http://localhost:3000/health` ); if (stdout.includes('ok')) { return true; } } catch (error) { // Container might not be ready yet } await new Promise(resolve => setTimeout(resolve, 500)); } return false; } /** * Check if a container is running in HTTP mode by verifying the server is listening */ export async function isRunningInHttpMode(containerName: string): Promise<boolean> { try { const { stdout } = await exec( `docker exec ${containerName} sh -c "netstat -tln 2>/dev/null | grep :3000 || echo 'Not listening'"` ); return stdout.includes(':3000'); } catch { return false; } } /** * Get process environment variables from inside a running container */ export async function getProcessEnv(containerName: string, varName: string): Promise<string | null> { try { const { stdout } = await exec( `docker exec ${containerName} sh -c "cat /proc/1/environ | tr '\\0' '\\n' | grep '^${varName}=' | cut -d= -f2-"` ); return stdout.trim() || null; } catch { return null; } } ``` -------------------------------------------------------------------------------- /tests/debug-slack-doc.js: -------------------------------------------------------------------------------- ```javascript #!/usr/bin/env node const { execSync } = require('child_process'); const path = require('path'); const tempDir = path.join(process.cwd(), 'temp', 'n8n-docs'); console.log('🔍 Debugging Slack documentation search...\n'); // Search for all Slack related files console.log('All Slack-related markdown files:'); try { const allSlackFiles = execSync( `find ${tempDir}/docs/integrations/builtin -name "*slack*.md" -type f`, { encoding: 'utf-8' } ).trim().split('\n'); allSlackFiles.forEach(file => { console.log(` - ${file}`); }); } catch (error) { console.log(' No files found'); } console.log('\n📄 Checking file paths:'); const possiblePaths = [ 'docs/integrations/builtin/app-nodes/n8n-nodes-base.Slack.md', 'docs/integrations/builtin/app-nodes/n8n-nodes-base.slack.md', 'docs/integrations/builtin/core-nodes/n8n-nodes-base.Slack.md', 'docs/integrations/builtin/core-nodes/n8n-nodes-base.slack.md', 'docs/integrations/builtin/trigger-nodes/n8n-nodes-base.Slack.md', 'docs/integrations/builtin/trigger-nodes/n8n-nodes-base.slack.md', 'docs/integrations/builtin/credentials/slack.md', ]; const fs = require('fs'); possiblePaths.forEach(p => { const fullPath = path.join(tempDir, p); const exists = fs.existsSync(fullPath); console.log(` ${exists ? '✓' : '✗'} ${p}`); if (exists) { // Read first few lines const content = fs.readFileSync(fullPath, 'utf-8'); const lines = content.split('\n').slice(0, 10); const title = lines.find(l => l.includes('title:')); if (title) { console.log(` Title: ${title.trim()}`); } } }); ``` -------------------------------------------------------------------------------- /scripts/analyze-optimization.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Analyze potential optimization savings echo "🔍 Analyzing Docker Optimization Potential" echo "==========================================" # Check current database size if [ -f data/nodes.db ]; then DB_SIZE=$(du -h data/nodes.db | cut -f1) echo "Current database size: $DB_SIZE" fi # Check node_modules size if [ -d node_modules ]; then echo -e "\n📦 Package sizes:" echo "Total node_modules: $(du -sh node_modules | cut -f1)" echo "n8n packages:" for pkg in n8n n8n-core n8n-workflow @n8n/n8n-nodes-langchain; do if [ -d "node_modules/$pkg" ]; then SIZE=$(du -sh "node_modules/$pkg" 2>/dev/null | cut -f1 || echo "N/A") echo " - $pkg: $SIZE" fi done fi # Check runtime dependencies echo -e "\n🎯 Runtime-only dependencies:" RUNTIME_DEPS="@modelcontextprotocol/sdk better-sqlite3 sql.js express dotenv" RUNTIME_SIZE=0 for dep in $RUNTIME_DEPS; do if [ -d "node_modules/$dep" ]; then SIZE=$(du -sh "node_modules/$dep" 2>/dev/null | cut -f1 || echo "0") echo " - $dep: $SIZE" fi done # Estimate savings echo -e "\n💡 Optimization potential:" echo "- Current image: 2.61GB" echo "- Estimated optimized: ~200MB" echo "- Savings: ~92%" # Show what would be removed echo -e "\n🗑️ Would remove in optimization:" echo "- n8n packages (>2GB)" echo "- Build dependencies" echo "- Documentation files" echo "- Test files" echo "- Source maps" # Check if optimized database exists if [ -f data/nodes-optimized.db ]; then OPT_SIZE=$(du -h data/nodes-optimized.db | cut -f1) echo -e "\n✅ Optimized database exists: $OPT_SIZE" fi ``` -------------------------------------------------------------------------------- /scripts/export-webhook-workflows.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env tsx /** * Export Webhook Workflow JSONs * * Generates the 4 webhook workflow JSON files needed for integration testing. * These workflows must be imported into n8n and activated manually. */ import { writeFileSync, mkdirSync } from 'fs'; import { join } from 'path'; import { exportAllWebhookWorkflows } from '../tests/integration/n8n-api/utils/webhook-workflows'; const OUTPUT_DIR = join(process.cwd(), 'workflows-for-import'); // Create output directory mkdirSync(OUTPUT_DIR, { recursive: true }); // Generate all workflow JSONs const workflows = exportAllWebhookWorkflows(); // Write each workflow to a separate file Object.entries(workflows).forEach(([method, workflow]) => { const filename = `webhook-${method.toLowerCase()}.json`; const filepath = join(OUTPUT_DIR, filename); writeFileSync(filepath, JSON.stringify(workflow, null, 2), 'utf-8'); console.log(`✓ Generated: ${filename}`); }); console.log(`\n✓ All workflow JSONs written to: ${OUTPUT_DIR}`); console.log('\nNext steps:'); console.log('1. Import each JSON file into your n8n instance'); console.log('2. Activate each workflow in the n8n UI'); console.log('3. Copy the webhook URLs from each workflow (open workflow → Webhook node → copy URL)'); console.log('4. Add them to your .env file:'); console.log(' N8N_TEST_WEBHOOK_GET_URL=https://your-n8n.com/webhook/mcp-test-get'); console.log(' N8N_TEST_WEBHOOK_POST_URL=https://your-n8n.com/webhook/mcp-test-post'); console.log(' N8N_TEST_WEBHOOK_PUT_URL=https://your-n8n.com/webhook/mcp-test-put'); console.log(' N8N_TEST_WEBHOOK_DELETE_URL=https://your-n8n.com/webhook/mcp-test-delete'); ``` -------------------------------------------------------------------------------- /.github/workflows/docker-build-fast.yml: -------------------------------------------------------------------------------- ```yaml # .github/workflows/docker-build-fast.yml name: Build Docker (AMD64 only - Fast) on: workflow_dispatch: pull_request: branches: - main paths: - 'Dockerfile' - 'package.runtime.json' - '.github/workflows/docker-build-fast.yml' env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-amd64: name: Build Docker Image (AMD64 only) runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v4 with: lfs: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=pr,suffix=-amd64 type=raw,value=test-amd64 - name: Build and push Docker image (AMD64 only) uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max provenance: false ``` -------------------------------------------------------------------------------- /scripts/test-telemetry-no-select.ts: -------------------------------------------------------------------------------- ```typescript #!/usr/bin/env npx tsx /** * Test telemetry without requesting data back */ import { createClient } from '@supabase/supabase-js'; import dotenv from 'dotenv'; dotenv.config(); async function testNoSelect() { const supabaseUrl = process.env.SUPABASE_URL!; const supabaseAnonKey = process.env.SUPABASE_ANON_KEY!; console.log('🧪 Telemetry Test (No Select)\n'); const supabase = createClient(supabaseUrl, supabaseAnonKey, { auth: { persistSession: false, autoRefreshToken: false, } }); // Insert WITHOUT .select() - just fire and forget const testData = { user_id: 'test-' + Date.now(), event: 'test_event', properties: { test: true } }; console.log('Inserting:', testData); const { error } = await supabase .from('telemetry_events') .insert([testData]); // No .select() here! if (error) { console.error('❌ Failed:', error); } else { console.log('✅ Success! Data inserted (no response data)'); } // Test workflow insert too const testWorkflow = { user_id: 'test-' + Date.now(), workflow_hash: 'hash-' + Date.now(), node_count: 3, node_types: ['webhook', 'http', 'slack'], has_trigger: true, has_webhook: true, complexity: 'simple', sanitized_workflow: { nodes: [], connections: {} } }; console.log('\nInserting workflow:', testWorkflow); const { error: workflowError } = await supabase .from('telemetry_workflows') .insert([testWorkflow]); // No .select() here! if (workflowError) { console.error('❌ Workflow failed:', workflowError); } else { console.log('✅ Workflow inserted successfully!'); } } testNoSelect().catch(console.error); ``` -------------------------------------------------------------------------------- /scripts/test-single-session.sh: -------------------------------------------------------------------------------- ```bash #!/bin/bash # Test script for single-session HTTP server set -e echo "🧪 Testing Single-Session HTTP Server..." echo # Generate test auth token if not set if [ -z "$AUTH_TOKEN" ]; then export AUTH_TOKEN="test-token-$(date +%s)" echo "Generated test AUTH_TOKEN: $AUTH_TOKEN" fi # Start server in background echo "Starting server..." MCP_MODE=http npm start > server.log 2>&1 & SERVER_PID=$! # Wait for server to start echo "Waiting for server to start..." sleep 3 # Check health endpoint echo echo "Testing health endpoint..." curl -s http://localhost:3000/health | jq . # Test authentication failure echo echo "Testing authentication failure..." curl -s -X POST http://localhost:3000/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer wrong-token" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' | jq . # Test successful request echo echo "Testing successful request..." curl -s -X POST http://localhost:3000/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $AUTH_TOKEN" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' | jq . # Test session reuse echo echo "Testing session reuse (second request)..." curl -s -X POST http://localhost:3000/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $AUTH_TOKEN" \ -d '{"jsonrpc":"2.0","method":"get_database_statistics","id":2}' | jq . # Check health again to see session info echo echo "Checking health to see session info..." curl -s http://localhost:3000/health | jq . # Clean up echo echo "Stopping server..." kill $SERVER_PID 2>/dev/null || true wait $SERVER_PID 2>/dev/null || true echo echo "✅ Test complete! Check server.log for details." ``` -------------------------------------------------------------------------------- /tests/integration/n8n-api/utils/n8n-client.ts: -------------------------------------------------------------------------------- ```typescript /** * Pre-configured n8n API Client for Integration Tests * * Provides a singleton API client instance configured with test credentials. * Automatically loads credentials from .env (local) or GitHub secrets (CI). */ import { N8nApiClient } from '../../../../src/services/n8n-api-client'; import { getN8nCredentials, validateCredentials } from './credentials'; let client: N8nApiClient | null = null; /** * Get or create the test n8n API client * * Creates a singleton instance configured with credentials from * the environment. Validates that required credentials are present. * * @returns Configured N8nApiClient instance * @throws Error if credentials are missing or invalid * * @example * const client = getTestN8nClient(); * const workflow = await client.createWorkflow({ ... }); */ export function getTestN8nClient(): N8nApiClient { if (!client) { const creds = getN8nCredentials(); validateCredentials(creds); client = new N8nApiClient({ baseUrl: creds.url, apiKey: creds.apiKey, timeout: 30000, maxRetries: 3 }); } return client; } /** * Reset the test client instance * * Forces recreation of the client on next call to getTestN8nClient(). * Useful for testing or when credentials change. */ export function resetTestN8nClient(): void { client = null; } /** * Check if the n8n API is accessible * * Performs a health check to verify API connectivity. * * @returns true if API is accessible, false otherwise */ export async function isN8nApiAccessible(): Promise<boolean> { try { const client = getTestN8nClient(); await client.healthCheck(); return true; } catch { return false; } } ``` -------------------------------------------------------------------------------- /tests/factories/node-factory.ts: -------------------------------------------------------------------------------- ```typescript import { Factory } from 'fishery'; import { faker } from '@faker-js/faker'; import { ParsedNode } from '../../src/parsers/node-parser'; /** * Factory for generating ParsedNode test data using Fishery. * Creates realistic node configurations with random but valid data. * * @example * ```typescript * // Create a single node with defaults * const node = NodeFactory.build(); * * // Create a node with specific properties * const slackNode = NodeFactory.build({ * nodeType: 'nodes-base.slack', * displayName: 'Slack', * isAITool: true * }); * * // Create multiple nodes * const nodes = NodeFactory.buildList(5); * * // Create with custom sequence * const sequencedNodes = NodeFactory.buildList(3, { * displayName: (i) => `Node ${i}` * }); * ``` */ export const NodeFactory = Factory.define<ParsedNode>(() => ({ nodeType: faker.helpers.arrayElement(['nodes-base.', 'nodes-langchain.']) + faker.word.noun(), displayName: faker.helpers.arrayElement(['HTTP', 'Slack', 'Google', 'AWS']) + ' ' + faker.word.noun(), description: faker.lorem.sentence(), packageName: faker.helpers.arrayElement(['n8n-nodes-base', '@n8n/n8n-nodes-langchain']), category: faker.helpers.arrayElement(['transform', 'trigger', 'output', 'input']), style: faker.helpers.arrayElement(['declarative', 'programmatic']), isAITool: faker.datatype.boolean(), isTrigger: faker.datatype.boolean(), isWebhook: faker.datatype.boolean(), isVersioned: faker.datatype.boolean(), version: faker.helpers.arrayElement(['1.0', '2.0', '3.0', '4.2']), documentation: faker.datatype.boolean() ? faker.lorem.paragraphs(3) : undefined, properties: [], operations: [], credentials: [] })); ```