#
tokens: 41374/50000 3/617 files (page 31/46)
lines: off (toggle) GitHub
raw markdown copy
This is page 31 of 46. Use http://codebase.md/czlonkowski/n8n-mcp?lines=false&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
│   ├── 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
├── LICENSE
├── MEMORY_N8N_UPDATE.md
├── MEMORY_TEMPLATE_UPDATE.md
├── monitor_fetch.sh
├── 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-sanitizer.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
│   │   └── 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
├── 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
│   │   │   ├── sqljs-memory-leak.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
│   │   ├── 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-sanitizer.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
│   │   ├── 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

--------------------------------------------------------------------------------
/src/services/task-templates.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Task Templates Service
 *
 * @deprecated This module is deprecated as of v2.15.0 and will be removed in v2.16.0.
 * The get_node_for_task tool has been removed in favor of template-based configuration examples.
 *
 * Migration:
 * - Use `search_nodes({query: "webhook", includeExamples: true})` to find nodes with real template configs
 * - Use `get_node_essentials({nodeType: "nodes-base.webhook", includeExamples: true})` for top 3 examples
 * - New approach provides 2,646 real templates vs 31 hardcoded tasks
 *
 * Provides pre-configured node settings for common tasks.
 * This helps AI agents quickly configure nodes for specific use cases.
 */

export interface TaskTemplate {
  task: string;
  description: string;
  nodeType: string;
  configuration: Record<string, any>;
  userMustProvide: Array<{
    property: string;
    description: string;
    example?: any;
  }>;
  optionalEnhancements?: Array<{
    property: string;
    description: string;
    when?: string;
  }>;
  notes?: string[];
}

export class TaskTemplates {
  private static templates: Record<string, TaskTemplate> = {
    // HTTP Request Tasks
    'get_api_data': {
      task: 'get_api_data',
      description: 'Make a simple GET request to retrieve data from an API',
      nodeType: 'nodes-base.httpRequest',
      configuration: {
        method: 'GET',
        url: '',
        authentication: 'none',
        // Default error handling for API calls
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 1000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'url',
          description: 'The API endpoint URL',
          example: 'https://api.example.com/users'
        }
      ],
      optionalEnhancements: [
        {
          property: 'authentication',
          description: 'Add authentication if the API requires it',
          when: 'API requires authentication'
        },
        {
          property: 'sendHeaders',
          description: 'Add custom headers if needed',
          when: 'API requires specific headers'
        },
        {
          property: 'alwaysOutputData',
          description: 'Set to true to capture error responses',
          when: 'Need to debug API errors'
        }
      ]
    },
    
    'post_json_request': {
      task: 'post_json_request',
      description: 'Send JSON data to an API endpoint',
      nodeType: 'nodes-base.httpRequest',
      configuration: {
        method: 'POST',
        url: '',
        sendBody: true,
        contentType: 'json',
        specifyBody: 'json',
        jsonBody: '',
        // POST requests might modify data, so be careful with retries
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 2,
        waitBetweenTries: 1000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'url',
          description: 'The API endpoint URL',
          example: 'https://api.example.com/users'
        },
        {
          property: 'jsonBody',
          description: 'The JSON data to send',
          example: '{\n  "name": "John Doe",\n  "email": "[email protected]"\n}'
        }
      ],
      optionalEnhancements: [
        {
          property: 'authentication',
          description: 'Add authentication if required'
        },
        {
          property: 'onError',
          description: 'Set to "continueRegularOutput" for non-critical operations',
          when: 'Failure should not stop the workflow'
        }
      ],
      notes: [
        'Make sure jsonBody contains valid JSON',
        'Content-Type header is automatically set to application/json',
        'Be careful with retries on non-idempotent operations'
      ]
    },
    
    'call_api_with_auth': {
      task: 'call_api_with_auth',
      description: 'Make an authenticated API request',
      nodeType: 'nodes-base.httpRequest',
      configuration: {
        method: 'GET',
        url: '',
        authentication: 'genericCredentialType',
        genericAuthType: 'headerAuth',
        sendHeaders: true,
        // Authentication calls should handle auth failures gracefully
        onError: 'continueErrorOutput',
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 2000,
        alwaysOutputData: true,
        headerParameters: {
          parameters: [
            {
              name: '',
              value: ''
            }
          ]
        }
      },
      userMustProvide: [
        {
          property: 'url',
          description: 'The API endpoint URL'
        },
        {
          property: 'headerParameters.parameters[0].name',
          description: 'The header name for authentication',
          example: 'Authorization'
        },
        {
          property: 'headerParameters.parameters[0].value',
          description: 'The authentication value',
          example: 'Bearer YOUR_API_KEY'
        }
      ],
      optionalEnhancements: [
        {
          property: 'method',
          description: 'Change to POST/PUT/DELETE as needed'
        }
      ]
    },
    
    // Webhook Tasks
    'receive_webhook': {
      task: 'receive_webhook',
      description: 'Set up a webhook to receive data from external services',
      nodeType: 'nodes-base.webhook',
      configuration: {
        httpMethod: 'POST',
        path: 'webhook',
        responseMode: 'lastNode',
        responseData: 'allEntries',
        // Webhooks should always respond, even on error
        onError: 'continueRegularOutput',
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'path',
          description: 'The webhook path (will be appended to your n8n URL)',
          example: 'github-webhook'
        }
      ],
      optionalEnhancements: [
        {
          property: 'httpMethod',
          description: 'Change if the service sends GET/PUT/etc'
        },
        {
          property: 'responseCode',
          description: 'Set custom response code (default 200)'
        }
      ],
      notes: [
        'The full webhook URL will be: https://your-n8n.com/webhook/[path]',
        'Test URL will be different from production URL'
      ]
    },
    
    'webhook_with_response': {
      task: 'webhook_with_response',
      description: 'Receive webhook and send custom response',
      nodeType: 'nodes-base.webhook',
      configuration: {
        httpMethod: 'POST',
        path: 'webhook',
        responseMode: 'responseNode',
        responseData: 'firstEntryJson',
        responseCode: 200,
        // Ensure webhook always sends response
        onError: 'continueRegularOutput',
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'path',
          description: 'The webhook path'
        }
      ],
      notes: [
        'Use with a Respond to Webhook node to send custom response',
        'responseMode: responseNode requires a Respond to Webhook node'
      ]
    },
    
    'process_webhook_data': {
      task: 'process_webhook_data',
      description: 'Process incoming webhook data with Code node (shows correct data access)',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// ⚠️ CRITICAL: Webhook data is nested under 'body' property!
// Connect this Code node after a Webhook node

// Access webhook payload data - it's under .body, not directly under .json
const webhookData = items[0].json.body;  // ✅ CORRECT
const headers = items[0].json.headers;   // HTTP headers
const query = items[0].json.query;       // Query parameters

// Common mistake to avoid:
// const command = items[0].json.testCommand;  // ❌ WRONG - will be undefined!
// const command = items[0].json.body.testCommand;  // ✅ CORRECT

// Process the webhook data
try {
  // Validate required fields
  if (!webhookData.command) {
    throw new Error('Missing required field: command');
  }
  
  // Process based on command
  let result = {};
  switch (webhookData.command) {
    case 'process':
      result = {
        status: 'processed',
        data: webhookData.data,
        processedAt: DateTime.now().toISO()
      };
      break;
      
    case 'validate':
      result = {
        status: 'validated',
        isValid: true,
        validatedFields: Object.keys(webhookData.data || {})
      };
      break;
      
    default:
      result = {
        status: 'unknown_command',
        command: webhookData.command
      };
  }
  
  // Return processed data
  return [{
    json: {
      ...result,
      requestId: headers['x-request-id'] || crypto.randomUUID(),
      source: query.source || 'webhook',
      originalCommand: webhookData.command,
      metadata: {
        httpMethod: items[0].json.httpMethod,
        webhookPath: items[0].json.webhookPath,
        timestamp: DateTime.now().toISO()
      }
    }
  }];
  
} catch (error) {
  // Return error response
  return [{
    json: {
      status: 'error',
      error: error.message,
      timestamp: DateTime.now().toISO()
    }
  }];
}`,
        onError: 'continueRegularOutput'
      },
      userMustProvide: [],
      notes: [
        '⚠️ WEBHOOK DATA IS AT items[0].json.body, NOT items[0].json',
        'This is the most common webhook processing mistake',
        'Headers are at items[0].json.headers',
        'Query parameters are at items[0].json.query',
        'Connect this Code node directly after a Webhook node'
      ]
    },
    
    // Database Tasks
    'query_postgres': {
      task: 'query_postgres',
      description: 'Query data from PostgreSQL database',
      nodeType: 'nodes-base.postgres',
      configuration: {
        operation: 'executeQuery',
        query: '',
        // Database reads can continue on error
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 1000
      },
      userMustProvide: [
        {
          property: 'query',
          description: 'The SQL query to execute',
          example: 'SELECT * FROM users WHERE active = true LIMIT 10'
        }
      ],
      optionalEnhancements: [
        {
          property: 'additionalFields.queryParams',
          description: 'Use parameterized queries for security',
          when: 'Using dynamic values'
        }
      ],
      notes: [
        'Always use parameterized queries to prevent SQL injection',
        'Configure PostgreSQL credentials in n8n'
      ]
    },
    
    'insert_postgres_data': {
      task: 'insert_postgres_data',
      description: 'Insert data into PostgreSQL table',
      nodeType: 'nodes-base.postgres',
      configuration: {
        operation: 'insert',
        table: '',
        columns: '',
        returnFields: '*',
        // Database writes should stop on error by default
        onError: 'stopWorkflow',
        retryOnFail: true,
        maxTries: 2,
        waitBetweenTries: 1000
      },
      userMustProvide: [
        {
          property: 'table',
          description: 'The table name',
          example: 'users'
        },
        {
          property: 'columns',
          description: 'Comma-separated column names',
          example: 'name,email,created_at'
        }
      ],
      notes: [
        'Input data should match the column structure',
        'Use expressions like {{ $json.fieldName }} to map data'
      ]
    },
    
    // AI/LangChain Tasks
    'chat_with_ai': {
      task: 'chat_with_ai',
      description: 'Send a message to an AI model and get response',
      nodeType: 'nodes-base.openAi',
      configuration: {
        resource: 'chat',
        operation: 'message',
        modelId: 'gpt-3.5-turbo',
        messages: {
          values: [
            {
              role: 'user',
              content: ''
            }
          ]
        },
        // AI calls should handle rate limits and API errors
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 5000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'messages.values[0].content',
          description: 'The message to send to the AI',
          example: '{{ $json.userMessage }}'
        }
      ],
      optionalEnhancements: [
        {
          property: 'modelId',
          description: 'Change to gpt-4 for better results'
        },
        {
          property: 'options.temperature',
          description: 'Adjust creativity (0-1)'
        },
        {
          property: 'options.maxTokens',
          description: 'Limit response length'
        }
      ]
    },
    
    'ai_agent_workflow': {
      task: 'ai_agent_workflow',
      description: 'Create an AI agent that can use tools',
      nodeType: 'nodes-langchain.agent',
      configuration: {
        text: '',
        outputType: 'output',
        systemMessage: 'You are a helpful assistant.'
      },
      userMustProvide: [
        {
          property: 'text',
          description: 'The input prompt for the agent',
          example: '{{ $json.query }}'
        }
      ],
      optionalEnhancements: [
        {
          property: 'systemMessage',
          description: 'Customize the agent\'s behavior'
        }
      ],
      notes: [
        'Connect tool nodes to give the agent capabilities',
        'Configure the AI model credentials'
      ]
    },
    
    // Data Processing Tasks
    'transform_data': {
      task: 'transform_data',
      description: 'Transform data structure using JavaScript',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Transform each item
const results = [];

for (const item of items) {
  results.push({
    json: {
      // Transform your data here
      id: item.json.id,
      processedAt: new Date().toISOString()
    }
  });
}

return results;`
      },
      userMustProvide: [],
      notes: [
        'Access input data via items array',
        'Each item has a json property with the data',
        'Return array of objects with json property'
      ]
    },
    
    'filter_data': {
      task: 'filter_data',
      description: 'Filter items based on conditions',
      nodeType: 'nodes-base.if',
      configuration: {
        conditions: {
          conditions: [
            {
              leftValue: '',
              rightValue: '',
              operator: {
                type: 'string',
                operation: 'equals'
              }
            }
          ]
        }
      },
      userMustProvide: [
        {
          property: 'conditions.conditions[0].leftValue',
          description: 'The value to check',
          example: '{{ $json.status }}'
        },
        {
          property: 'conditions.conditions[0].rightValue',
          description: 'The value to compare against',
          example: 'active'
        }
      ],
      notes: [
        'True output contains matching items',
        'False output contains non-matching items'
      ]
    },
    
    // Communication Tasks
    'send_slack_message': {
      task: 'send_slack_message',
      description: 'Send a message to Slack channel',
      nodeType: 'nodes-base.slack',
      configuration: {
        resource: 'message',
        operation: 'post',
        channel: '',
        text: '',
        // Messaging can continue on error
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 2,
        waitBetweenTries: 2000
      },
      userMustProvide: [
        {
          property: 'channel',
          description: 'The Slack channel',
          example: '#general'
        },
        {
          property: 'text',
          description: 'The message text',
          example: 'New order received: {{ $json.orderId }}'
        }
      ],
      optionalEnhancements: [
        {
          property: 'attachments',
          description: 'Add rich message attachments'
        },
        {
          property: 'blocks',
          description: 'Use Block Kit for advanced formatting'
        }
      ]
    },
    
    'send_email': {
      task: 'send_email',
      description: 'Send an email notification',
      nodeType: 'nodes-base.emailSend',
      configuration: {
        fromEmail: '',
        toEmail: '',
        subject: '',
        text: '',
        // Email sending should retry on transient failures
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 3000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'fromEmail',
          description: 'Sender email address',
          example: '[email protected]'
        },
        {
          property: 'toEmail',
          description: 'Recipient email address',
          example: '{{ $json.customerEmail }}'
        },
        {
          property: 'subject',
          description: 'Email subject',
          example: 'Order Confirmation #{{ $json.orderId }}'
        },
        {
          property: 'text',
          description: 'Email body (plain text)',
          example: 'Thank you for your order!'
        }
      ],
      optionalEnhancements: [
        {
          property: 'html',
          description: 'Use HTML for rich formatting'
        },
        {
          property: 'attachments',
          description: 'Attach files to the email'
        }
      ]
    },
    
    // AI Tool Usage Tasks
    'use_google_sheets_as_tool': {
      task: 'use_google_sheets_as_tool',
      description: 'Use Google Sheets as an AI tool for reading/writing data',
      nodeType: 'nodes-base.googleSheets',
      configuration: {
        operation: 'append',
        sheetId: '={{ $fromAI("sheetId", "The Google Sheets ID") }}',
        range: '={{ $fromAI("range", "The range to append to, e.g. A:Z") }}',
        dataMode: 'autoMap'
      },
      userMustProvide: [
        {
          property: 'Google Sheets credentials',
          description: 'Configure Google Sheets API credentials in n8n'
        },
        {
          property: 'Tool name in AI Agent',
          description: 'Give it a descriptive name like "Log Results to Sheet"'
        },
        {
          property: 'Tool description',
          description: 'Describe when and how the AI should use this tool'
        }
      ],
      notes: [
        'Connect this node to the ai_tool port of an AI Agent node',
        'The AI can dynamically determine sheetId and range using $fromAI',
        'Works great for logging AI analysis results or reading data for processing'
      ]
    },
    
    'use_slack_as_tool': {
      task: 'use_slack_as_tool',
      description: 'Use Slack as an AI tool for sending notifications',
      nodeType: 'nodes-base.slack',
      configuration: {
        resource: 'message',
        operation: 'post',
        channel: '={{ $fromAI("channel", "The Slack channel, e.g. #general") }}',
        text: '={{ $fromAI("message", "The message to send") }}',
        attachments: []
      },
      userMustProvide: [
        {
          property: 'Slack credentials',
          description: 'Configure Slack OAuth2 credentials in n8n'
        },
        {
          property: 'Tool configuration in AI Agent',
          description: 'Name it something like "Send Slack Notification"'
        }
      ],
      notes: [
        'Perfect for AI agents that need to notify teams',
        'The AI determines channel and message content dynamically',
        'Can be enhanced with blocks for rich formatting'
      ]
    },
    
    'multi_tool_ai_agent': {
      task: 'multi_tool_ai_agent',
      description: 'AI agent with multiple tools for complex automation',
      nodeType: 'nodes-langchain.agent',
      configuration: {
        text: '={{ $json.query }}',
        outputType: 'output',
        systemMessage: 'You are an intelligent assistant with access to multiple tools. Use them wisely to complete tasks.'
      },
      userMustProvide: [
        {
          property: 'AI model credentials',
          description: 'OpenAI, Anthropic, or other LLM credentials'
        },
        {
          property: 'Multiple tool nodes',
          description: 'Connect various nodes to the ai_tool port'
        },
        {
          property: 'Tool descriptions',
          description: 'Clear descriptions for each connected tool'
        }
      ],
      optionalEnhancements: [
        {
          property: 'Memory',
          description: 'Add memory nodes for conversation context'
        },
        {
          property: 'Custom tools',
          description: 'Create Code nodes as custom tools'
        }
      ],
      notes: [
        'Connect multiple nodes: HTTP Request, Slack, Google Sheets, etc.',
        'Each tool should have a clear, specific purpose',
        'Test each tool individually before combining',
        'Set N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true for community nodes'
      ]
    },
    
    // Error Handling Templates
    'api_call_with_retry': {
      task: 'api_call_with_retry',
      description: 'Resilient API call with automatic retry on failure',
      nodeType: 'nodes-base.httpRequest',
      configuration: {
        method: 'GET',
        url: '',
        // Retry configuration for transient failures
        retryOnFail: true,
        maxTries: 5,
        waitBetweenTries: 2000,
        // Always capture response for debugging
        alwaysOutputData: true,
        // Add request tracking
        sendHeaders: true,
        headerParameters: {
          parameters: [
            {
              name: 'X-Request-ID',
              value: '={{ $workflow.id }}-{{ $itemIndex }}'
            }
          ]
        }
      },
      userMustProvide: [
        {
          property: 'url',
          description: 'The API endpoint to call',
          example: 'https://api.example.com/resource/{{ $json.id }}'
        }
      ],
      optionalEnhancements: [
        {
          property: 'authentication',
          description: 'Add API authentication'
        },
        {
          property: 'onError',
          description: 'Change to "stopWorkflow" for critical API calls',
          when: 'This is a critical API call that must succeed'
        }
      ],
      notes: [
        'Retries help with rate limits and transient network issues',
        'waitBetweenTries prevents hammering the API',
        'alwaysOutputData captures error responses for debugging',
        'Consider exponential backoff for production use'
      ]
    },
    
    'fault_tolerant_processing': {
      task: 'fault_tolerant_processing',
      description: 'Data processing that continues despite individual item failures',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Process items with error handling
const results = [];

for (const item of items) {
  try {
    // Your processing logic here
    const processed = {
      ...item.json,
      processed: true,
      timestamp: new Date().toISOString()
    };
    
    results.push({ json: processed });
  } catch (error) {
    // Log error but continue processing
    console.error('Processing failed for item:', item.json.id, error);
    
    // Add error item to results
    results.push({
      json: {
        ...item.json,
        error: error.message,
        processed: false
      }
    });
  }
}

return results;`,
        // Continue workflow even if code fails entirely
        onError: 'continueRegularOutput',
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'Processing logic',
          description: 'Replace the comment with your data transformation logic'
        }
      ],
      optionalEnhancements: [
        {
          property: 'Error notification',
          description: 'Add IF node after to handle error items separately'
        }
      ],
      notes: [
        'Individual item failures won\'t stop processing of other items',
        'Error items are marked and can be handled separately',
        'continueOnFail ensures workflow continues even on total failure'
      ]
    },
    
    'webhook_with_error_handling': {
      task: 'webhook_with_error_handling',
      description: 'Webhook that gracefully handles processing errors',
      nodeType: 'nodes-base.webhook',
      configuration: {
        httpMethod: 'POST',
        path: 'resilient-webhook',
        responseMode: 'responseNode',
        responseData: 'firstEntryJson',
        // Always continue to ensure response is sent
        onError: 'continueRegularOutput',
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'path',
          description: 'Unique webhook path',
          example: 'order-processor'
        },
        {
          property: 'Respond to Webhook node',
          description: 'Add node to send appropriate success/error responses'
        }
      ],
      optionalEnhancements: [
        {
          property: 'Validation',
          description: 'Add IF node to validate webhook payload'
        },
        {
          property: 'Error logging',
          description: 'Add error handler node for failed requests'
        }
      ],
      notes: [
        'onError: continueRegularOutput ensures webhook always sends a response',
        'Use Respond to Webhook node to send appropriate status codes',
        'Log errors but don\'t expose internal errors to webhook callers',
        'Consider rate limiting for public webhooks'
      ]
    },
    
    // Modern Error Handling Patterns
    'modern_error_handling_patterns': {
      task: 'modern_error_handling_patterns',
      description: 'Examples of modern error handling using onError property',
      nodeType: 'nodes-base.httpRequest',
      configuration: {
        method: 'GET',
        url: '',
        // Modern error handling approach
        onError: 'continueRegularOutput', // Options: continueRegularOutput, continueErrorOutput, stopWorkflow
        retryOnFail: true,
        maxTries: 3,
        waitBetweenTries: 2000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'url',
          description: 'The API endpoint'
        },
        {
          property: 'onError',
          description: 'Choose error handling strategy',
          example: 'continueRegularOutput'
        }
      ],
      notes: [
        'onError replaces the deprecated continueOnFail property',
        'continueRegularOutput: Continue with normal output on error',
        'continueErrorOutput: Route errors to error output for special handling', 
        'stopWorkflow: Stop the entire workflow on error',
        'Combine with retryOnFail for resilient workflows'
      ]
    },
    
    'database_transaction_safety': {
      task: 'database_transaction_safety',
      description: 'Database operations with proper error handling',
      nodeType: 'nodes-base.postgres',
      configuration: {
        operation: 'executeQuery',
        query: 'BEGIN; INSERT INTO orders ...; COMMIT;',
        // For transactions, don\'t retry automatically
        onError: 'continueErrorOutput',
        retryOnFail: false,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'query',
          description: 'Your SQL query or transaction'
        }
      ],
      notes: [
        'Transactions should not be retried automatically',
        'Use continueErrorOutput to handle errors separately',
        'Consider implementing compensating transactions',
        'Always log transaction failures for audit'
      ]
    },
    
    'ai_rate_limit_handling': {
      task: 'ai_rate_limit_handling',
      description: 'AI API calls with rate limit handling',
      nodeType: 'nodes-base.openAi',
      configuration: {
        resource: 'chat',
        operation: 'message',
        modelId: 'gpt-4',
        messages: {
          values: [
            {
              role: 'user',
              content: ''
            }
          ]
        },
        // Handle rate limits with exponential backoff
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 5,
        waitBetweenTries: 5000,
        alwaysOutputData: true
      },
      userMustProvide: [
        {
          property: 'messages.values[0].content',
          description: 'The prompt for the AI'
        }
      ],
      notes: [
        'AI APIs often have rate limits',
        'Longer wait times help avoid hitting limits',
        'Consider implementing exponential backoff in Code node',
        'Monitor usage to stay within quotas'
      ]
    },
    
    // Code Node Tasks
    'custom_ai_tool': {
      task: 'custom_ai_tool',
      description: 'Create a custom tool for AI agents using Code node',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        mode: 'runOnceForEachItem',
        jsCode: `// Custom AI Tool - Example: Text Analysis
// This code will be called by AI agents with $json containing the input

// Access the input from the AI agent
const text = $json.text || '';
const operation = $json.operation || 'analyze';

// Perform the requested operation
let result = {};

switch (operation) {
  case 'wordCount':
    result = {
      wordCount: text.split(/\\s+/).filter(word => word.length > 0).length,
      characterCount: text.length,
      lineCount: text.split('\\n').length
    };
    break;
    
  case 'extract':
    // Extract specific patterns (emails, URLs, etc.)
    result = {
      emails: text.match(/[\\w.-]+@[\\w.-]+\\.\\w+/g) || [],
      urls: text.match(/https?:\\/\\/[^\\s]+/g) || [],
      numbers: text.match(/\\b\\d+\\b/g) || []
    };
    break;
    
  default:
    result = {
      error: 'Unknown operation',
      availableOperations: ['wordCount', 'extract']
    };
}

return [{
  json: {
    ...result,
    originalText: text,
    operation: operation,
    processedAt: DateTime.now().toISO()
  }
}];`,
        onError: 'continueRegularOutput'
      },
      userMustProvide: [],
      notes: [
        'Connect this to AI Agent node\'s tool input',
        'AI will pass data in $json',
        'Use "Run Once for Each Item" mode for AI tools',
        'Return structured data the AI can understand'
      ]
    },
    
    'aggregate_data': {
      task: 'aggregate_data',
      description: 'Aggregate data from multiple items into summary statistics',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Aggregate data from all items
const stats = {
  count: 0,
  sum: 0,
  min: Infinity,
  max: -Infinity,
  values: [],
  categories: {},
  errors: []
};

// Process each item
for (const item of items) {
  try {
    const value = item.json.value || item.json.amount || 0;
    const category = item.json.category || 'uncategorized';
    
    stats.count++;
    stats.sum += value;
    stats.min = Math.min(stats.min, value);
    stats.max = Math.max(stats.max, value);
    stats.values.push(value);
    
    // Count by category
    stats.categories[category] = (stats.categories[category] || 0) + 1;
    
  } catch (error) {
    stats.errors.push({
      item: item.json,
      error: error.message
    });
  }
}

// Calculate additional statistics
const average = stats.count > 0 ? stats.sum / stats.count : 0;
const sorted = [...stats.values].sort((a, b) => a - b);
const median = sorted.length > 0 
  ? sorted[Math.floor(sorted.length / 2)] 
  : 0;

return [{
  json: {
    totalItems: stats.count,
    sum: stats.sum,
    average: average,
    median: median,
    min: stats.min === Infinity ? 0 : stats.min,
    max: stats.max === -Infinity ? 0 : stats.max,
    categoryCounts: stats.categories,
    errorCount: stats.errors.length,
    errors: stats.errors,
    processedAt: DateTime.now().toISO()
  }
}];`,
        onError: 'continueRegularOutput'
      },
      userMustProvide: [],
      notes: [
        'Assumes items have "value" or "amount" field',
        'Groups by "category" field if present',
        'Returns single item with all statistics',
        'Handles errors gracefully'
      ]
    },
    
    'batch_process_with_api': {
      task: 'batch_process_with_api',
      description: 'Process items in batches with API calls',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Batch process items with API calls
const BATCH_SIZE = 10;
const API_URL = 'https://api.example.com/batch-process'; // USER MUST UPDATE
const results = [];

// Process items in batches
for (let i = 0; i < items.length; i += BATCH_SIZE) {
  const batch = items.slice(i, i + BATCH_SIZE);
  
  try {
    // Prepare batch data
    const batchData = batch.map(item => ({
      id: item.json.id,
      data: item.json
    }));
    
    // Make API request for batch
    const response = await $helpers.httpRequest({
      method: 'POST',
      url: API_URL,
      body: {
        items: batchData
      },
      headers: {
        'Content-Type': 'application/json'
      }
    });
    
    // Add results
    if (response.results && Array.isArray(response.results)) {
      response.results.forEach((result, index) => {
        results.push({
          json: {
            ...batch[index].json,
            ...result,
            batchNumber: Math.floor(i / BATCH_SIZE) + 1,
            processedAt: DateTime.now().toISO()
          }
        });
      });
    }
    
    // Add delay between batches to avoid rate limits
    if (i + BATCH_SIZE < items.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
    
  } catch (error) {
    // Add failed batch items with error
    batch.forEach(item => {
      results.push({
        json: {
          ...item.json,
          error: error.message,
          status: 'failed',
          batchNumber: Math.floor(i / BATCH_SIZE) + 1
        }
      });
    });
  }
}

return results;`,
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 2
      },
      userMustProvide: [
        {
          property: 'jsCode',
          description: 'Update API_URL in the code',
          example: 'https://your-api.com/batch'
        }
      ],
      notes: [
        'Processes items in batches of 10',
        'Includes delay between batches',
        'Handles batch failures gracefully',
        'Update API_URL and adjust BATCH_SIZE as needed'
      ]
    },
    
    'error_safe_transform': {
      task: 'error_safe_transform',
      description: 'Transform data with comprehensive error handling',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Safe data transformation with validation
const results = [];
const errors = [];

for (const item of items) {
  try {
    // Validate required fields
    const required = ['id', 'name']; // USER SHOULD UPDATE
    const missing = required.filter(field => !item.json[field]);
    
    if (missing.length > 0) {
      throw new Error(\`Missing required fields: \${missing.join(', ')}\`);
    }
    
    // Transform data with type checking
    const transformed = {
      // Ensure ID is string
      id: String(item.json.id),
      
      // Clean and validate name
      name: String(item.json.name).trim(),
      
      // Parse numbers safely
      amount: parseFloat(item.json.amount) || 0,
      
      // Parse dates safely
      date: item.json.date 
        ? DateTime.fromISO(item.json.date).isValid 
          ? DateTime.fromISO(item.json.date).toISO()
          : null
        : null,
      
      // Boolean conversion
      isActive: Boolean(item.json.active || item.json.isActive),
      
      // Array handling
      tags: Array.isArray(item.json.tags) 
        ? item.json.tags.filter(tag => typeof tag === 'string')
        : [],
      
      // Nested object handling
      metadata: typeof item.json.metadata === 'object' 
        ? item.json.metadata 
        : {},
      
      // Add processing info
      processedAt: DateTime.now().toISO(),
      originalIndex: items.indexOf(item)
    };
    
    results.push({
      json: transformed
    });
    
  } catch (error) {
    errors.push({
      json: {
        error: error.message,
        originalData: item.json,
        index: items.indexOf(item),
        status: 'failed'
      }
    });
  }
}

// Add summary at the end
results.push({
  json: {
    _summary: {
      totalProcessed: results.length - errors.length,
      totalErrors: errors.length,
      successRate: ((results.length - errors.length) / items.length * 100).toFixed(2) + '%',
      timestamp: DateTime.now().toISO()
    }
  }
});

// Include errors at the end
return [...results, ...errors];`,
        onError: 'continueRegularOutput'
      },
      userMustProvide: [
        {
          property: 'jsCode',
          description: 'Update required fields array',
          example: "const required = ['id', 'email', 'name'];"
        }
      ],
      notes: [
        'Validates all data types',
        'Handles missing/invalid data gracefully',
        'Returns both successful and failed items',
        'Includes processing summary'
      ]
    },
    
    'async_data_processing': {
      task: 'async_data_processing',
      description: 'Process data with async operations and proper error handling',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'javaScript',
        jsCode: `// Async processing with concurrent limits
const CONCURRENT_LIMIT = 5;
const results = [];

// Process items with concurrency control
async function processItem(item, index) {
  try {
    // Simulate async operation (replace with actual logic)
    // Example: API call, database query, file operation
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // Actual processing logic here
    const processed = {
      ...item.json,
      processed: true,
      index: index,
      timestamp: DateTime.now().toISO()
    };
    
    // Example async operation - external API call
    if (item.json.needsEnrichment) {
      const enrichment = await $helpers.httpRequest({
        method: 'GET',
        url: \`https://api.example.com/enrich/\${item.json.id}\`
      });
      processed.enrichment = enrichment;
    }
    
    return { json: processed };
    
  } catch (error) {
    return {
      json: {
        ...item.json,
        error: error.message,
        status: 'failed',
        index: index
      }
    };
  }
}

// Process in batches with concurrency limit
for (let i = 0; i < items.length; i += CONCURRENT_LIMIT) {
  const batch = items.slice(i, i + CONCURRENT_LIMIT);
  const batchPromises = batch.map((item, batchIndex) => 
    processItem(item, i + batchIndex)
  );
  
  const batchResults = await Promise.all(batchPromises);
  results.push(...batchResults);
}

return results;`,
        onError: 'continueRegularOutput',
        retryOnFail: true,
        maxTries: 2
      },
      userMustProvide: [],
      notes: [
        'Processes 5 items concurrently',
        'Prevents overwhelming external services',
        'Each item processed independently',
        'Errors don\'t affect other items'
      ]
    },
    
    'python_data_analysis': {
      task: 'python_data_analysis',
      description: 'Analyze data using Python with statistics',
      nodeType: 'nodes-base.code',
      configuration: {
        language: 'python',
        pythonCode: `# Python data analysis - use underscore prefix for built-in variables
import json
from datetime import datetime
import statistics

# Collect data for analysis
values = []
categories = {}
dates = []

# Use _input.all() to get items in Python
for item in _input.all():
    # Convert JsProxy to Python dict for safe access
    item_data = item.json.to_py()
    
    # Extract numeric values
    if 'value' in item_data or 'amount' in item_data:
        value = item_data.get('value', item_data.get('amount', 0))
        if isinstance(value, (int, float)):
            values.append(value)
    
    # Count categories
    category = item_data.get('category', 'uncategorized')
    categories[category] = categories.get(category, 0) + 1
    
    # Collect dates
    if 'date' in item_data:
        dates.append(item_data['date'])

# Calculate statistics
result = {
    'itemCount': len(_input.all()),
    'values': {
        'count': len(values),
        'sum': sum(values) if values else 0,
        'mean': statistics.mean(values) if values else 0,
        'median': statistics.median(values) if values else 0,
        'min': min(values) if values else 0,
        'max': max(values) if values else 0,
        'stdev': statistics.stdev(values) if len(values) > 1 else 0
    },
    'categories': categories,
    'dateRange': {
        'earliest': min(dates) if dates else None,
        'latest': max(dates) if dates else None,
        'count': len(dates)
    },
    'analysis': {
        'hasNumericData': len(values) > 0,
        'hasCategoricalData': len(categories) > 0,
        'hasTemporalData': len(dates) > 0,
        'dataQuality': 'good' if len(values) > len(items) * 0.8 else 'partial'
    },
    'processedAt': datetime.now().isoformat()
}

# Return single summary item
return [{'json': result}]`,
        onError: 'continueRegularOutput'
      },
      userMustProvide: [],
      notes: [
        'Uses Python statistics module',
        'Analyzes numeric, categorical, and date data',
        'Returns comprehensive summary',
        'Handles missing data gracefully'
      ]
    }
  };
  
  /**
   * Get all available tasks
   */
  static getAllTasks(): string[] {
    return Object.keys(this.templates);
  }
  
  /**
   * Get tasks for a specific node type
   */
  static getTasksForNode(nodeType: string): string[] {
    return Object.entries(this.templates)
      .filter(([_, template]) => template.nodeType === nodeType)
      .map(([task, _]) => task);
  }
  
  /**
   * Get a specific task template
   */
  static getTaskTemplate(task: string): TaskTemplate | undefined {
    return this.templates[task];
  }
  
  /**
   * Get a specific task template (alias for getTaskTemplate)
   */
  static getTemplate(task: string): TaskTemplate | undefined {
    return this.getTaskTemplate(task);
  }
  
  /**
   * Search for tasks by keyword
   */
  static searchTasks(keyword: string): string[] {
    const lower = keyword.toLowerCase();
    return Object.entries(this.templates)
      .filter(([task, template]) => 
        task.toLowerCase().includes(lower) ||
        template.description.toLowerCase().includes(lower) ||
        template.nodeType.toLowerCase().includes(lower)
      )
      .map(([task, _]) => task);
  }
  
  /**
   * Get task categories
   */
  static getTaskCategories(): Record<string, string[]> {
    return {
      'HTTP/API': ['get_api_data', 'post_json_request', 'call_api_with_auth', 'api_call_with_retry'],
      'Webhooks': ['receive_webhook', 'webhook_with_response', 'webhook_with_error_handling', 'process_webhook_data'],
      'Database': ['query_postgres', 'insert_postgres_data', 'database_transaction_safety'],
      'AI/LangChain': ['chat_with_ai', 'ai_agent_workflow', 'multi_tool_ai_agent', 'ai_rate_limit_handling'],
      'Data Processing': ['transform_data', 'filter_data', 'fault_tolerant_processing', 'process_webhook_data'],
      'Communication': ['send_slack_message', 'send_email'],
      'AI Tool Usage': ['use_google_sheets_as_tool', 'use_slack_as_tool', 'multi_tool_ai_agent'],
      'Error Handling': ['modern_error_handling_patterns', 'api_call_with_retry', 'fault_tolerant_processing', 'webhook_with_error_handling', 'database_transaction_safety', 'ai_rate_limit_handling']
    };
  }
}
```

--------------------------------------------------------------------------------
/docs/local/P0_IMPLEMENTATION_PLAN.md:
--------------------------------------------------------------------------------

```markdown
# P0 Priorities Implementation Plan
## Critical Fixes for n8n-mcp Based on Production Telemetry Data

**Date:** October 2, 2025
**Analysis Period:** September 26 - October 2, 2025
**Data Volume:** 212,375 events | 5,751 workflows | 2,119 users
**Target:** Reduce error rate from 5-10% to <2%

---

## Executive Summary

This document provides a comprehensive implementation plan for the three P0 (Priority 0 - Critical) issues identified through deep analysis of production telemetry data. These fixes will eliminate **80% of all validation errors** and significantly improve the AI agent experience.

### Impact Summary

| Issue | Current Failure Rate | Post-Fix Target | Affected Users | Estimated Effort |
|-------|---------------------|-----------------|----------------|------------------|
| **P0-R1**: Node Type Prefix Normalization | 80% of validation errors | <1% | Hundreds | 2 days |
| **P0-R2**: Null-Safety Audit | 10-18% TypeError rate | <1% | 30+ | 2 days |
| **P0-R3**: Pre-extract Template Configs + Remove get_node_for_task | 28% failure rate, 5.9% coverage | N/A (tool removed), 100% coverage | 197 (migrated) | 5 days |

**Total Effort:** 2 weeks (v2.15.0 release)

---

## Table of Contents

1. [P0-R1: Auto-Normalize Node Type Prefixes](#p0-r1-auto-normalize-node-type-prefixes)
2. [P0-R2: Complete Null-Safety Audit](#p0-r2-complete-null-safety-audit)
3. [P0-R3: Pre-extract Template Configurations + Remove get_node_for_task](#p0-r3-pre-extract-template-configurations--remove-get_node_for_task)
4. [Implementation Order & Timeline](#implementation-order--timeline)
5. [Testing Strategy](#testing-strategy)
6. [Rollback Plan](#rollback-plan)
7. [Success Metrics](#success-metrics)

---

## P0-R1: Auto-Normalize Node Type Prefixes

### Problem Statement

**Impact:** 4,800+ validation errors (80% of all validation errors) from a single root cause

AI agents frequently produce `nodes-base.X` instead of `n8n-nodes-base.X`, causing validation failures. This is the single largest source of user frustration.

**Example Error:**
```
Error: Invalid node type: "nodes-base.set". Use "n8n-nodes-base.set" instead.
```

### Root Cause Analysis

**Current Implementation Issues:**

1. **Existing normalization is BACKWARD:**
   - `src/utils/node-type-utils.ts` normalizes TO short form (`nodes-base.`)
   - But validation expects full form (`n8n-nodes-base.`)
   - This is the **opposite** of what we need

2. **Location of the bug:**
   ```typescript
   // src/utils/node-type-utils.ts:18-20
   return type
     .replace(/^n8n-nodes-base\./, 'nodes-base.')  // ❌ WRONG DIRECTION
     .replace(/^@n8n\/n8n-nodes-langchain\./, 'nodes-langchain.');
   ```

3. **Why AI agents produce short form:**
   - Token efficiency (LLMs abbreviate to save tokens)
   - Pattern learning from examples
   - Natural language preference for concise names

### Solution Architecture

**Strategy:** Normalize ALL node types to FULL form before validation

#### 1. Create Universal Node Type Normalizer

**File:** `src/utils/node-type-normalizer.ts` (NEW)

```typescript
/**
 * Universal Node Type Normalizer
 *
 * Converts ANY node type variation to the canonical full form expected by n8n
 *
 * Handles:
 * - Short form → Full form (nodes-base.X → n8n-nodes-base.X)
 * - Already full form → Unchanged
 * - LangChain nodes → Proper @n8n/ prefix
 */

export interface NodeTypeNormalizationResult {
  original: string;
  normalized: string;
  wasNormalized: boolean;
  package: 'base' | 'langchain' | 'community' | 'unknown';
}

export class NodeTypeNormalizer {

  /**
   * Normalize node type to canonical full form
   *
   * @example
   * normalizeToFullForm('nodes-base.webhook')
   * // → 'n8n-nodes-base.webhook'
   *
   * normalizeToFullForm('n8n-nodes-base.webhook')
   * // → 'n8n-nodes-base.webhook' (unchanged)
   *
   * normalizeToFullForm('nodes-langchain.agent')
   * // → '@n8n/n8n-nodes-langchain.agent'
   */
  static normalizeToFullForm(type: string): string {
    if (!type || typeof type !== 'string') {
      return type;
    }

    // Already in full form - return unchanged
    if (type.startsWith('n8n-nodes-base.')) {
      return type;
    }
    if (type.startsWith('@n8n/n8n-nodes-langchain.')) {
      return type;
    }

    // Normalize short forms to full form
    if (type.startsWith('nodes-base.')) {
      return type.replace(/^nodes-base\./, 'n8n-nodes-base.');
    }
    if (type.startsWith('nodes-langchain.')) {
      return type.replace(/^nodes-langchain\./, '@n8n/n8n-nodes-langchain.');
    }
    if (type.startsWith('n8n-nodes-langchain.')) {
      return type.replace(/^n8n-nodes-langchain\./, '@n8n/n8n-nodes-langchain.');
    }

    // No prefix - might be community node or error
    return type;
  }

  /**
   * Normalize with detailed result
   */
  static normalizeWithDetails(type: string): NodeTypeNormalizationResult {
    const original = type;
    const normalized = this.normalizeToFullForm(type);

    return {
      original,
      normalized,
      wasNormalized: original !== normalized,
      package: this.detectPackage(normalized)
    };
  }

  /**
   * Detect package type from node type
   */
  private static detectPackage(type: string): 'base' | 'langchain' | 'community' | 'unknown' {
    if (type.startsWith('n8n-nodes-base.')) return 'base';
    if (type.startsWith('@n8n/n8n-nodes-langchain.')) return 'langchain';
    if (type.includes('.')) return 'community';
    return 'unknown';
  }

  /**
   * Batch normalize multiple node types
   */
  static normalizeBatch(types: string[]): Map<string, string> {
    const result = new Map<string, string>();
    for (const type of types) {
      result.set(type, this.normalizeToFullForm(type));
    }
    return result;
  }

  /**
   * Normalize all node types in a workflow
   */
  static normalizeWorkflowNodeTypes(workflow: any): any {
    if (!workflow?.nodes || !Array.isArray(workflow.nodes)) {
      return workflow;
    }

    return {
      ...workflow,
      nodes: workflow.nodes.map((node: any) => ({
        ...node,
        type: this.normalizeToFullForm(node.type)
      }))
    };
  }
}
```

#### 2. Apply Normalization in All Entry Points

**File:** `src/services/workflow-validator.ts`

**Change at line 250:** (validateWorkflowStructure method)

```typescript
// BEFORE (line 250-252):
const normalizedType = normalizeNodeType(singleNode.type);
const isWebhook = normalizedType === 'nodes-base.webhook' ||
                 normalizedType === 'nodes-base.webhookTrigger';

// AFTER:
import { NodeTypeNormalizer } from '../utils/node-type-normalizer';

const normalizedType = NodeTypeNormalizer.normalizeToFullForm(singleNode.type);
const isWebhook = normalizedType === 'n8n-nodes-base.webhook' ||
                 normalizedType === 'n8n-nodes-base.webhookTrigger';
```

**Change at line 368-376:** (validateAllNodes method)

```typescript
// BEFORE:
// Get node definition - try multiple formats
let nodeInfo = this.nodeRepository.getNode(node.type);

// If not found, try with normalized type
if (!nodeInfo) {
  const normalizedType = normalizeNodeType(node.type);
  if (normalizedType !== node.type) {
    nodeInfo = this.nodeRepository.getNode(normalizedType);
  }
}

// AFTER:
// Normalize node type FIRST
const normalizedType = NodeTypeNormalizer.normalizeToFullForm(node.type);
const nodeInfo = this.nodeRepository.getNode(normalizedType);

// Update node type in place if normalized
if (normalizedType !== node.type) {
  node.type = normalizedType;
}
```

**File:** `src/mcp/handlers-n8n-manager.ts`

**Add normalization in handleCreateWorkflow (line 281-310):**

```typescript
// BEFORE validation:
const input = createWorkflowSchema.parse(args);

// AFTER: Add normalization
const input = createWorkflowSchema.parse(args);

// Normalize all node types before validation
const normalizedInput = NodeTypeNormalizer.normalizeWorkflowNodeTypes(input);

// Validate workflow structure
const errors = validateWorkflowStructure(normalizedInput);
```

**Apply same pattern to:**
- `handleUpdateWorkflow` (line 520)
- `validateWorkflow` tool handler
- Any other workflow creation/update entry points

#### 3. Update Node Repository for Flexible Lookups

**File:** `src/database/node-repository.ts`

**Enhance getNode method (line 54):**

```typescript
/**
 * Get node with automatic type normalization
 */
getNode(nodeType: string): any {
  // Try normalized type first
  const normalizedType = NodeTypeNormalizer.normalizeToFullForm(nodeType);

  const row = this.db.prepare(`
    SELECT * FROM nodes WHERE node_type = ?
  `).get(normalizedType) as any;

  if (!row) {
    // Fallback: try original type if normalization didn't help
    if (normalizedType !== nodeType) {
      const originalRow = this.db.prepare(`
        SELECT * FROM nodes WHERE node_type = ?
      `).get(nodeType) as any;

      if (originalRow) return this.parseNodeRow(originalRow);
    }
    return null;
  }

  return this.parseNodeRow(row);
}
```

### Testing Requirements

**File:** `tests/unit/utils/node-type-normalizer.test.ts` (NEW)

```typescript
describe('NodeTypeNormalizer', () => {
  describe('normalizeToFullForm', () => {
    it('should normalize short base form to full form', () => {
      expect(NodeTypeNormalizer.normalizeToFullForm('nodes-base.webhook'))
        .toBe('n8n-nodes-base.webhook');
    });

    it('should normalize short langchain form to full form', () => {
      expect(NodeTypeNormalizer.normalizeToFullForm('nodes-langchain.agent'))
        .toBe('@n8n/n8n-nodes-langchain.agent');
    });

    it('should leave full forms unchanged', () => {
      expect(NodeTypeNormalizer.normalizeToFullForm('n8n-nodes-base.webhook'))
        .toBe('n8n-nodes-base.webhook');
    });

    it('should handle edge cases', () => {
      expect(NodeTypeNormalizer.normalizeToFullForm('')).toBe('');
      expect(NodeTypeNormalizer.normalizeToFullForm(null as any)).toBe(null);
    });
  });

  describe('normalizeWorkflowNodeTypes', () => {
    it('should normalize all nodes in workflow', () => {
      const workflow = {
        nodes: [
          { type: 'nodes-base.webhook', id: '1', name: 'Webhook' },
          { type: 'nodes-base.set', id: '2', name: 'Set' }
        ],
        connections: {}
      };

      const result = NodeTypeNormalizer.normalizeWorkflowNodeTypes(workflow);

      expect(result.nodes[0].type).toBe('n8n-nodes-base.webhook');
      expect(result.nodes[1].type).toBe('n8n-nodes-base.set');
    });
  });
});
```

### Success Criteria

- [x] All workflow validation tests pass with both short and full node type forms
- [x] 0 "Invalid node type" errors for variations of core nodes
- [x] Telemetry shows <1% validation errors related to node type prefixes
- [x] No breaking changes to existing workflows

**Status:** ✅ COMPLETED (October 2, 2025)
**Commit:** ed7de10

### Estimated Effort

**Total: 2-4 hours**

- Implementation: 1-2 hours
- Testing: 1 hour
- Documentation: 30 minutes
- Code review: 30 minutes

---

## P0-R2: Complete Null-Safety Audit

### Problem Statement

**Impact:** 10-18% TypeError failures in node information tools affecting 1,000+ calls

```
TypeError: Cannot read property 'text' of undefined
```

**Affected Tools:**
- `get_node_essentials`: 483 failures (10% of 4,909 calls)
- `get_node_info`: 352 failures (18% of 1,988 calls)
- `get_node_documentation`: 136 failures (7% of 1,919 calls)

### Root Cause Analysis

**From CHANGELOG 2.14.0:**
> "Fixed TypeErrors in get_node_info, get_node_essentials, and get_node_documentation tools"
> "Added null safety checks for undefined node properties"

**The fix was incomplete.** Residual issues remain in:

1. Nested property access without guards
2. Edge cases with unusual/legacy node structures
3. Missing properties in database
4. Assumptions about property structure

### Current Implementation Analysis

**File:** `src/database/node-repository.ts`

**Problem areas identified:**

```typescript
// Line 73-78: Good - has safeJsonParse
properties: this.safeJsonParse(row.properties_schema, []),
operations: this.safeJsonParse(row.operations, []),
credentials: this.safeJsonParse(row.credentials_required, []),

// But doesn't protect against:
// - properties being null after parse
// - Nested properties like properties[0].description.text
// - Missing fields in properties array
```

**handlers for get_node_essentials/info need to be found and audited**

### Solution Architecture

#### 1. Enhanced Safe Property Access Utilities

**File:** `src/utils/safe-property-access.ts` (NEW)

```typescript
/**
 * Safe Property Access Utilities
 *
 * Provides defensive property access with fallbacks
 */

export class SafePropertyAccess {
  /**
   * Safely get nested property with default
   */
  static get<T>(obj: any, path: string, defaultValue: T): T {
    if (!obj || typeof obj !== 'object') return defaultValue;

    const keys = path.split('.');
    let current = obj;

    for (const key of keys) {
      if (current === null || current === undefined) {
        return defaultValue;
      }
      if (typeof current !== 'object') {
        return defaultValue;
      }
      current = current[key];
    }

    return current !== undefined ? current : defaultValue;
  }

  /**
   * Safely get array with default
   */
  static getArray<T>(obj: any, path: string, defaultValue: T[] = []): T[] {
    const value = this.get(obj, path, defaultValue);
    return Array.isArray(value) ? value : defaultValue;
  }

  /**
   * Safely get string with default
   */
  static getString(obj: any, path: string, defaultValue: string = ''): string {
    const value = this.get(obj, path, defaultValue);
    return typeof value === 'string' ? value : defaultValue;
  }

  /**
   * Safely get number with default
   */
  static getNumber(obj: any, path: string, defaultValue: number = 0): number {
    const value = this.get(obj, path, defaultValue);
    return typeof value === 'number' && !isNaN(value) ? value : defaultValue;
  }

  /**
   * Safely get boolean with default
   */
  static getBoolean(obj: any, path: string, defaultValue: boolean = false): boolean {
    const value = this.get(obj, path, defaultValue);
    return typeof value === 'boolean' ? value : defaultValue;
  }

  /**
   * Extract description from multiple possible locations
   */
  static extractDescription(obj: any): string {
    // Try common description locations
    const locations = [
      'description',
      'properties.description',
      'properties.description.text',
      'subtitle',
      'displayName'
    ];

    for (const location of locations) {
      const value = this.getString(obj, location);
      if (value) return value;
    }

    return 'No description available';
  }

  /**
   * Extract display name from multiple possible locations
   */
  static extractDisplayName(obj: any, fallback: string = 'Unknown'): string {
    const locations = [
      'displayName',
      'name',
      'label',
      'title'
    ];

    for (const location of locations) {
      const value = this.getString(obj, location);
      if (value) return value;
    }

    return fallback;
  }
}
```

#### 2. Null-Safe Node Repository Methods

**File:** `src/database/node-repository.ts`

**Refactor getNode method (line 54):**

```typescript
import { SafePropertyAccess } from '../utils/safe-property-access';

/**
 * Get node with comprehensive null-safety
 */
getNode(nodeType: string): any | null {
  try {
    // Normalize type first
    const normalizedType = NodeTypeNormalizer.normalizeToFullForm(nodeType);

    const row = this.db.prepare(`
      SELECT * FROM nodes WHERE node_type = ?
    `).get(normalizedType) as any;

    if (!row) return null;

    // Use safe property access for all fields
    return {
      nodeType: SafePropertyAccess.getString(row, 'node_type', normalizedType),
      displayName: SafePropertyAccess.extractDisplayName(row,
        SafePropertyAccess.getString(row, 'display_name', 'Unknown Node')),
      description: SafePropertyAccess.extractDescription(row),
      category: SafePropertyAccess.getString(row, 'category', 'Uncategorized'),
      developmentStyle: SafePropertyAccess.getString(row, 'development_style', 'declarative'),
      package: SafePropertyAccess.getString(row, 'package_name', 'unknown'),
      isAITool: SafePropertyAccess.getBoolean(row, 'is_ai_tool', false),
      isTrigger: SafePropertyAccess.getBoolean(row, 'is_trigger', false),
      isWebhook: SafePropertyAccess.getBoolean(row, 'is_webhook', false),
      isVersioned: SafePropertyAccess.getBoolean(row, 'is_versioned', false),
      version: SafePropertyAccess.getNumber(row, 'version', 1),
      properties: this.safeParseProperties(row.properties_schema),
      operations: this.safeParseArray(row.operations),
      credentials: this.safeParseArray(row.credentials_required),
      hasDocumentation: !!row.documentation,
      outputs: row.outputs ? this.safeJsonParse(row.outputs, null) : null,
      outputNames: row.output_names ? this.safeJsonParse(row.output_names, null) : null
    };
  } catch (error) {
    console.error(`Error getting node ${nodeType}:`, error);
    return null;
  }
}

/**
 * Safely parse properties with validation
 */
private safeParseProperties(json: string): any[] {
  try {
    const parsed = JSON.parse(json);
    if (!Array.isArray(parsed)) return [];

    // Validate each property has minimum required fields
    return parsed.map(prop => ({
      name: SafePropertyAccess.getString(prop, 'name', 'unknown'),
      displayName: SafePropertyAccess.extractDisplayName(prop),
      type: SafePropertyAccess.getString(prop, 'type', 'string'),
      required: SafePropertyAccess.getBoolean(prop, 'required', false),
      default: prop.default !== undefined ? prop.default : null,
      description: SafePropertyAccess.extractDescription(prop),
      options: SafePropertyAccess.getArray(prop, 'options', []),
      displayOptions: prop.displayOptions || null
    }));
  } catch {
    return [];
  }
}

/**
 * Safely parse array field
 */
private safeParseArray(json: string): any[] {
  try {
    const parsed = JSON.parse(json);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
}
```

#### 3. Find and Fix Handler Functions

**Action Required:** Search for handler functions that call getNode and add null checks

**Pattern to search for:**
```bash
grep -r "getNode\|getNodeEssentials\|getNodeInfo" src/mcp/ --include="*.ts"
```

**Add null checks like:**
```typescript
const node = repository.getNode(nodeType);
if (!node) {
  return {
    success: false,
    error: `Node type "${nodeType}" not found. Use search_nodes to find available nodes.`
  };
}
```

### Testing Requirements

**File:** `tests/unit/database/node-repository-null-safety.test.ts` (NEW)

```typescript
describe('NodeRepository - Null Safety', () => {
  it('should handle node with missing description', () => {
    // Insert node with minimal data
    const node = { type: 'test.node', name: 'Test' };
    db.prepare('INSERT INTO nodes (node_type, display_name) VALUES (?, ?)').run(node.type, node.name);

    const result = repository.getNode('test.node');
    expect(result).not.toBeNull();
    expect(result.description).toBe('No description available');
    expect(result.properties).toEqual([]);
  });

  it('should handle node with malformed JSON', () => {
    db.prepare('INSERT INTO nodes (node_type, properties_schema) VALUES (?, ?)').run('test.node', 'invalid json');

    const result = repository.getNode('test.node');
    expect(result).not.toBeNull();
    expect(result.properties).toEqual([]);
  });

  it('should handle non-existent node gracefully', () => {
    const result = repository.getNode('non.existent');
    expect(result).toBeNull();
  });

  it('should handle null database row', () => {
    // Simulate database returning null
    const result = repository.getNode('null.node');
    expect(result).toBeNull();
  });
});
```

### Success Criteria

- [ ] get_node_essentials failure rate: 10% → <1%
- [ ] get_node_info failure rate: 18% → <1%
- [ ] get_node_documentation failure rate: 7% → <1%
- [ ] 100% test coverage for null cases
- [ ] No TypeErrors in production logs

### Estimated Effort

**Total: 1 day (8 hours)**

- Safe property access utility: 2 hours
- Repository refactoring: 3 hours
- Handler updates: 2 hours
- Testing: 1 hour

---

## P0-R3: Pre-extract Template Configurations + Remove get_node_for_task

### Problem Statement

**Impact:** 28% failure rate (worst-performing tool) + redundant with better alternatives

`get_node_for_task` failing 109 times out of 392 calls (27.8%)

**Current State:**
- Only 31 predefined tasks in `task-templates.ts` (5.9% node coverage)
- 22.5:1 usage ratio favoring `search_nodes` (8,839 calls vs 392)
- Hardcoded configurations require manual maintenance
- Tool provides no unique value over `search_nodes`

**Discovery:** We have 2,646 real production workflow templates from n8n.io with:
- 3,820 httpRequest configurations
- 1,700 googleSheets configurations
- 466 webhook configurations
- 100% AI-generated metadata coverage
- Real-world best practices and patterns

### Architectural Decision: Pre-extraction

**Analysis:** On-the-fly vs Pre-extraction (see `/docs/local/TEMPLATE_MINING_ANALYSIS.md`)

**Decision:** Pre-extract node configurations into separate table

**Rationale:**
- **Performance:** 1ms vs 30-60ms (30-60x faster)
- **Storage:** Only 513 KB for 2,625 configs (negligible)
- **Simplicity:** No cache management, TTL, or eviction logic
- **Features:** Enables filtering by complexity, auth (indexed queries)
- **Scalability:** Handles 10,000+ templates without degradation
- **Predictability:** Consistent sub-millisecond response times

**Trade-offs (acceptable):**
- +30-60 seconds rebuild time (rare operation)
- Incremental updates needed when templates change

### Solution Architecture

**Strategy:**
1. Pre-extract top 10 node configurations per node type into new table
2. Enhance `get_node_essentials` with optional examples
3. Enhance `search_nodes` with optional examples
4. **Remove** `get_node_for_task` entirely (no redirect)

See `/docs/local/TEMPLATE_MINING_ANALYSIS.md` for complete analysis

#### 1. Add Database Schema for Pre-extracted Configurations

**File:** `src/database/schema.sql`

Add new table after `templates` table:

```sql
-- Pre-extracted node configurations from templates
CREATE TABLE template_node_configs (
  id INTEGER PRIMARY KEY,
  node_type TEXT NOT NULL,
  template_id INTEGER NOT NULL,
  template_name TEXT NOT NULL,
  template_views INTEGER DEFAULT 0,

  -- Node configuration (extracted from workflow)
  node_name TEXT,                  -- Node name in workflow (e.g., "HTTP Request")
  parameters_json TEXT NOT NULL,   -- JSON: node.parameters
  credentials_json TEXT,            -- JSON: node.credentials (if present)

  -- Pre-calculated metadata for filtering
  has_credentials INTEGER DEFAULT 0,
  has_expressions INTEGER DEFAULT 0,  -- Contains {{...}} or $json/$node
  complexity TEXT CHECK(complexity IN ('simple', 'medium', 'complex')),
  use_cases TEXT,                   -- JSON array from template.metadata.use_cases

  -- Pre-calculated ranking (1 = best, 2 = second best, etc.)
  rank INTEGER DEFAULT 0,

  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE CASCADE
);

-- Indexes for fast queries
CREATE INDEX idx_config_node_type_rank
  ON template_node_configs(node_type, rank);

CREATE INDEX idx_config_complexity
  ON template_node_configs(node_type, complexity, rank);

CREATE INDEX idx_config_auth
  ON template_node_configs(node_type, has_credentials, rank);

-- View for easy querying of top configs
CREATE VIEW ranked_node_configs AS
SELECT
  node_type,
  template_name,
  template_views,
  parameters_json,
  credentials_json,
  has_credentials,
  has_expressions,
  complexity,
  use_cases,
  rank
FROM template_node_configs
WHERE rank <= 5  -- Top 5 per node type
ORDER BY node_type, rank;
```

**Migration Script:** `src/database/migrations/add-template-node-configs.sql`

```sql
-- Migration for existing databases
-- Run during `npm run rebuild` or `npm run fetch:templates`

-- Check if table exists
CREATE TABLE IF NOT EXISTS template_node_configs (
  -- ... schema as above
);

-- Populate from existing templates
-- (handled by extraction logic in fetch:templates script)
```

#### 2. Add Extraction Logic to fetch:templates Script

**File:** `src/scripts/fetch-templates.ts`

Add extraction function:

```typescript
import gzip from 'zlib';

/**
 * Extract node configurations from a template workflow
 */
function extractNodeConfigs(
  templateId: number,
  templateName: string,
  templateViews: number,
  workflowCompressed: string,
  metadata: any
): Array<{
  node_type: string;
  template_id: number;
  template_name: string;
  template_views: number;
  node_name: string;
  parameters_json: string;
  credentials_json: string | null;
  has_credentials: number;
  has_expressions: number;
  complexity: string;
  use_cases: string;
}> {
  try {
    // Decompress workflow
    const decompressed = gzip.gunzipSync(Buffer.from(workflowCompressed, 'base64'));
    const workflow = JSON.parse(decompressed.toString('utf-8'));

    const configs: any[] = [];

    for (const node of workflow.nodes || []) {
      // Skip UI-only nodes
      if (node.type.includes('stickyNote') || !node.parameters) {
        continue;
      }

      configs.push({
        node_type: node.type,
        template_id: templateId,
        template_name: templateName,
        template_views: templateViews,
        node_name: node.name,
        parameters_json: JSON.stringify(node.parameters),
        credentials_json: node.credentials ? JSON.stringify(node.credentials) : null,
        has_credentials: node.credentials ? 1 : 0,
        has_expressions: detectExpressions(node.parameters) ? 1 : 0,
        complexity: metadata?.complexity || 'medium',
        use_cases: JSON.stringify(metadata?.use_cases || [])
      });
    }

    return configs;
  } catch (error) {
    console.error(`Error extracting configs from template ${templateId}:`, error);
    return [];
  }
}

/**
 * Detect n8n expressions in parameters
 */
function detectExpressions(params: any): boolean {
  const json = JSON.stringify(params);
  return json.includes('={{') || json.includes('$json') || json.includes('$node');
}

/**
 * Insert extracted configs into database and rank them
 */
function insertAndRankConfigs(db: Database, configs: any[]) {
  // Clear old configs for these templates
  const templateIds = [...new Set(configs.map(c => c.template_id))];
  db.prepare(`DELETE FROM template_node_configs WHERE template_id IN (${templateIds.join(',')})`).run();

  // Insert new configs
  const insertStmt = db.prepare(`
    INSERT INTO template_node_configs (
      node_type, template_id, template_name, template_views,
      node_name, parameters_json, credentials_json,
      has_credentials, has_expressions, complexity, use_cases
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `);

  for (const config of configs) {
    insertStmt.run(
      config.node_type,
      config.template_id,
      config.template_name,
      config.template_views,
      config.node_name,
      config.parameters_json,
      config.credentials_json,
      config.has_credentials,
      config.has_expressions,
      config.complexity,
      config.use_cases
    );
  }

  // Rank configs per node_type by template popularity
  db.exec(`
    UPDATE template_node_configs
    SET rank = (
      SELECT COUNT(*) + 1
      FROM template_node_configs AS t2
      WHERE t2.node_type = template_node_configs.node_type
        AND t2.template_views > template_node_configs.template_views
    )
  `);

  // Keep only top 10 per node_type
  db.exec(`
    DELETE FROM template_node_configs
    WHERE id NOT IN (
      SELECT id FROM template_node_configs
      WHERE rank <= 10
    )
  `);

  console.log(`Extracted and ranked ${configs.length} node configurations`);
}
```

#### 3. Enhance get_node_essentials with Examples

**File:** `src/mcp/handlers-*.ts` or `src/mcp/server.ts`

Update `get_node_essentials` handler:

```typescript
async function getNodeEssentials(
  nodeType: string,
  options?: { includeExamples?: boolean }
): Promise<any> {
  const node = repository.getNode(nodeType);
  if (!node) {
    return {
      success: false,
      error: `Node type "${nodeType}" not found. Use search_nodes to find available nodes.`
    };
  }

  const result = {
    nodeType,
    displayName: node.displayName,
    description: node.description,
    category: node.category,
    // ... existing essentials fields ...
  };

  // NEW: Add real-world examples if requested
  if (options?.includeExamples) {
    const examples = db.prepare(`
      SELECT
        parameters_json,
        template_name,
        template_views,
        complexity,
        use_cases,
        has_credentials,
        has_expressions
      FROM template_node_configs
      WHERE node_type = ?
      ORDER BY rank
      LIMIT 3
    `).all(nodeType);

    result.examples = examples.map(ex => ({
      config: JSON.parse(ex.parameters_json),
      source: `${ex.template_name} (${(ex.template_views / 1000).toFixed(0)}k views)`,
      complexity: ex.complexity,
      useCases: JSON.parse(ex.use_cases).slice(0, 2),
      hasAuth: ex.has_credentials === 1,
      hasExpressions: ex.has_expressions === 1
    }));
  }

  return result;
}
```

**Tool definition update:**

```typescript
{
  name: 'get_node_essentials',
  description: 'Get essential information about a specific n8n node type...',
  inputSchema: {
    type: 'object',
    properties: {
      nodeType: {
        type: 'string',
        description: 'Full node type (e.g., "n8n-nodes-base.httpRequest")'
      },
      includeExamples: {  // NEW
        type: 'boolean',
        description: 'Include 2-3 real configuration examples from popular templates',
        default: false
      }
    },
    required: ['nodeType']
  }
}
```

#### 4. Enhance search_nodes with Examples

**File:** `src/mcp/handlers-*.ts` or `src/mcp/server.ts`

Update `search_nodes` handler:

```typescript
async function searchNodes(
  query: string,
  options?: {
    limit?: number;
    includeExamples?: boolean;
  }
): Promise<any> {
  const nodes = repository.searchNodes(query, 'OR', options?.limit || 20);

  const results = nodes.map(node => {
    const result = {
      nodeType: node.nodeType,
      displayName: node.displayName,
      description: node.description,
      category: node.category
    };

    // NEW: Add examples if requested
    if (options?.includeExamples) {
      const examples = db.prepare(`
        SELECT parameters_json, template_name, complexity
        FROM template_node_configs
        WHERE node_type = ?
        ORDER BY rank
        LIMIT 2
      `).all(node.nodeType);

      result.examples = examples.map(ex => ({
        config: JSON.parse(ex.parameters_json),
        source: ex.template_name,
        complexity: ex.complexity
      }));
    }

    return result;
  });

  return results;
}
```

**Tool definition update:**

```typescript
{
  name: 'search_nodes',
  description: 'Search for n8n nodes by keyword...',
  inputSchema: {
    type: 'object',
    properties: {
      query: { type: 'string', description: 'Search query' },
      limit: { type: 'number', default: 20 },
      includeExamples: {  // NEW
        type: 'boolean',
        description: 'Include 2 real configuration examples per node',
        default: false
      }
    },
    required: ['query']
  }
}
```

#### 5. Remove get_node_for_task Tool Entirely

**Files to modify:**

1. **`src/mcp/server.ts`** - Remove handler function
2. **`src/mcp/tools.ts`** - Remove tool definition
3. **`src/mcp/tools-documentation.ts`** - Remove from documentation
4. **`src/services/task-templates.ts`** - Can be deprecated (keep for now, remove in v2.16.0)
5. **`README.md`** - Remove from available tools list
6. **`CHANGELOG.md`** - Document removal

**Steps:**

```bash
# Search for all references
grep -r "get_node_for_task" src/
grep -r "getNodeForTask" src/

# Remove handler
# Remove tool definition
# Remove from documentation
# Update README
```

**Migration note for users (add to CHANGELOG):**

```markdown
### BREAKING CHANGES in v2.15.0

- **Removed:** `get_node_for_task` tool
  - **Replacement:** Use `search_nodes` with `includeExamples: true`
  - **Migration:** `get_node_for_task({task: "webhook"})` → `search_nodes({query: "webhook", includeExamples: true})`
  - **Benefit:** Access to 2,646 real templates vs 31 hardcoded tasks
```

### Testing Requirements

**File:** `tests/unit/services/template-config-extraction.test.ts` (NEW)

```typescript
describe('Template Config Extraction', () => {
  it('should extract node configs from workflow', () => {
    const workflow = {
      nodes: [
        {
          type: 'n8n-nodes-base.httpRequest',
          name: 'HTTP Request',
          parameters: { url: 'https://api.example.com', method: 'GET' }
        }
      ]
    };

    const configs = extractNodeConfigs(1, 'Test', 1000, compressWorkflow(workflow), {});
    expect(configs).toHaveLength(1);
    expect(configs[0].node_type).toBe('n8n-nodes-base.httpRequest');
  });

  it('should detect expressions in parameters', () => {
    const params = { url: '={{$json.api_url}}' };
    expect(detectExpressions(params)).toBe(true);
  });

  it('should rank configs by popularity', () => {
    // Insert configs with different views
    // Verify ranking order
  });
});
```

**File:** `tests/integration/enhanced-tools.test.ts` (NEW)

```typescript
describe('Enhanced Tools with Examples', () => {
  it('get_node_essentials should return examples when requested', async () => {
    const result = await getNodeEssentials('n8n-nodes-base.httpRequest', {
      includeExamples: true
    });

    expect(result.examples).toBeDefined();
    expect(result.examples.length).toBeGreaterThan(0);
    expect(result.examples[0].config).toHaveProperty('url');
  });

  it('search_nodes should return examples when requested', async () => {
    const result = await searchNodes('webhook', { includeExamples: true });

    expect(result.length).toBeGreaterThan(0);
    expect(result[0].examples).toBeDefined();
  });

  it('get_node_for_task should not exist', async () => {
    expect(toolRegistry.has('get_node_for_task')).toBe(false);
  });
});
```

### Success Criteria

- [ ] Extract 2,000+ node configurations from templates
- [ ] Query performance: <1ms for pre-extracted configs
- [ ] `get_node_essentials` with examples: <5ms total
- [ ] `search_nodes` with examples: <10ms total
- [ ] Database size increase: <1 MB
- [ ] `get_node_for_task` completely removed from codebase
- [ ] All documentation updated

### Estimated Effort

**Total: 1 week (5 days)**

- **Day 1:** Database schema + migration (8 hours)
  - Design schema
  - Create migration script
  - Test with existing database

- **Day 2:** Extraction logic in fetch:templates (8 hours)
  - Write extraction function
  - Write ranking logic
  - Test with 2,646 templates

- **Day 3:** Enhance get_node_essentials + search_nodes (8 hours)
  - Add includeExamples parameter
  - Update tool definitions
  - Integration testing

- **Day 4:** Remove get_node_for_task + documentation (8 hours)
  - Remove from all files
  - Update README, CHANGELOG
  - Update tools_documentation
  - Migration guide

- **Day 5:** Testing + optimization (8 hours)
  - Unit tests
  - Integration tests
  - Performance testing
  - Bug fixes

---

## Implementation Order & Timeline

### Version 2.15.0 - All P0 Fixes in One Release

**Total Timeline:** 2 weeks (10 working days)

### Week 1: Foundation + P0-R1 + P0-R2

**Monday (Day 1-2): P0-R1 - Node Type Normalization**
- AM: Create NodeTypeNormalizer utility
- PM: Apply to workflow validator, handlers, and repository
- Testing and validation
- **Deliverable:** 80% of validation errors eliminated

**Tuesday (Day 3): P0-R2 - Null-Safety Audit (Part 1)**
- AM: Create SafePropertyAccess utility
- PM: Refactor node repository methods
- **Deliverable:** Safe property access framework

**Wednesday (Day 4): P0-R2 - Null-Safety Audit (Part 2)**
- AM: Find and fix all handlers
- PM: Comprehensive null-safety testing
- **Deliverable:** 10-18% TypeError rate → <1%

**Thursday (Day 5): P0-R3 - Database Schema**
- AM: Design and implement template_node_configs table
- PM: Create migration script and test with existing database
- **Deliverable:** Schema ready for extraction

**Friday (Day 6): P0-R3 - Extraction Logic**
- AM: Write extraction function in fetch:templates
- PM: Write ranking logic and test with 2,646 templates
- **Deliverable:** 2,000+ configs extracted and ranked

### Week 2: P0-R3 Integration + Testing + Documentation

**Monday (Day 7): Tool Enhancements**
- AM: Enhance get_node_essentials with includeExamples
- PM: Enhance search_nodes with includeExamples
- **Deliverable:** Both tools return real examples

**Tuesday (Day 8): Tool Removal + Documentation**
- AM: Remove get_node_for_task from all files
- PM: Update README, CHANGELOG, tools_documentation
- **Deliverable:** Clean removal, migration guide complete

**Wednesday (Day 9): Comprehensive Testing**
- AM: Unit tests for extraction and enhanced tools
- PM: Integration tests for all P0 fixes
- **Deliverable:** 95%+ test coverage

**Thursday (Day 10): Performance + Final Testing**
- AM: Performance testing and optimization
- PM: E2E testing and bug fixes
- **Deliverable:** All success criteria met

**Friday (Day 11): Release Preparation**
- AM: Code review and documentation review
- PM: Prepare release notes, tag v2.15.0
- **Deliverable:** Ready for release

### Parallel Activities

- **Documentation updates:** Days 1-11
- **Code reviews:** End of Days 2, 4, 6, 8, 10
- **Telemetry preparation:** Day 10-11 (prepare monitoring dashboard)

---

## Testing Strategy

### Unit Tests

**Coverage Target:** 95% for new code

- **Node Type Normalizer:** 20+ test cases
- **Safe Property Access:** 30+ test cases
- **Task Discovery Service:** 40+ test cases

### Integration Tests

- Workflow validation with mixed node type forms
- Node repository with edge case data
- Task discovery with real node database

### E2E Tests

- Create workflow with short-form node types → Should succeed
- Get node info for nodes with missing properties → Should return safe defaults
- Query task discovery with variations → Should find matches

### Regression Tests

- All existing tests must pass
- No breaking changes to public APIs

### Performance Tests

- Normalization overhead: <1ms per workflow
- Safe property access: <0.1ms per node
- Task discovery: <50ms average

---

## Rollback Plan

### If P0-R1 Causes Issues

1. **Symptom:** Workflows fail validation after normalization
2. **Action:** Revert node-type-normalizer changes
3. **Fallback:** Use original normalizeNodeType
4. **Recovery time:** 15 minutes

### If P0-R2 Causes Performance Issues

1. **Symptom:** Node lookup becomes slow
2. **Action:** Cache safe property access results
3. **Fallback:** Keep safe parsing but reduce validation
4. **Recovery time:** 1 hour

### If P0-R3 Template Extraction Causes Issues

1. **Symptom:** Database bloat or slow queries
2. **Action:** Reduce rank limit from 10 to 5 per node
3. **Fallback:** Disable includeExamples parameter temporarily
4. **Recovery time:** 15 minutes (just disable parameter)

### If get_node_for_task Removal Causes User Issues

1. **Symptom:** Users report missing tool
2. **Action:** Add prominent migration guide to error messages
3. **Fallback:** N/A (breaking change, users must migrate)
4. **Communication:** Update docs, add migration examples

---

## Success Metrics

### Overall Goals

| Metric | Current | Target | How to Measure |
|--------|---------|--------|----------------|
| Overall error rate | 5-10% | <2% | Telemetry events |
| Validation errors | 4,800/week | <100/week | Error logs |
| TypeError rate | 10-18% | <1% | Tool execution logs |
| Node configs extracted | 0 | 2,000+ | Database count |
| Config query performance | N/A | <1ms | Performance tests |
| get_node_for_task usage | 392 calls | 0 (removed) | Tool usage stats |
| search_nodes w/ examples | 0 | Monitored | New feature adoption |

### Telemetry Monitoring

After deployment, monitor for 1 week:

- Error rate by tool (should decrease 80-90%)
- User success rate (should increase 5-10%)
- Average errors per user (should decrease from 2.5 to <0.5)

---

## Dependencies

### NPM Packages

No new NPM packages required - all functionality uses existing dependencies.

### Internal Dependencies

- **P0-R3** requires database schema update (template_node_configs table)
- **P0-R3** requires migration script for existing databases
- All changes are backward compatible except removal of `get_node_for_task`

---

## Documentation Updates

### Files to Update

1. **CHANGELOG.md** - Add entries for each P0 fix + breaking changes
2. **README.md** - Remove get_node_for_task, add includeExamples parameter
3. **src/mcp/tools-documentation.ts** - Remove get_node_for_task documentation
4. **API.md** - Document enhanced tool parameters
5. **MIGRATION.md** - Add migration guide from get_node_for_task to search_nodes (NEW)

### Example CHANGELOG Entry

```markdown
## [2.15.0] - 2025-10-09

### BREAKING CHANGES
- **Removed:** `get_node_for_task` tool
  - **Replacement:** Use `search_nodes` with `includeExamples: true`
  - **Migration:** `get_node_for_task({task: "webhook"})` → `search_nodes({query: "webhook", includeExamples: true})`
  - **Benefit:** Access to 2,646 real templates vs 31 hardcoded tasks

### Fixed
- **P0-R1:** Auto-normalize node type prefixes (eliminates 80% of validation errors)
- **P0-R2:** Complete null-safety audit for node information tools (reduces TypeError failures from 10-18% to <1%)

### Added
- `NodeTypeNormalizer` utility for universal node type normalization
- `SafePropertyAccess` utility for defensive property access
- `template_node_configs` table with 2,000+ pre-extracted configurations
- `includeExamples` parameter for `get_node_essentials` (returns 2-3 real configs)
- `includeExamples` parameter for `search_nodes` (returns 2 real configs per node)
- Real-world configuration examples from popular n8n templates

### Performance
- Node configuration queries: <1ms (30-60x faster than on-the-fly extraction)
- Sub-millisecond response time for configuration examples
```

---

## Conclusion

These P0 fixes represent the highest-impact improvements we can make to n8n-mcp based on real production telemetry data. By implementing all three fixes in v2.15.0, we will:

1. **Eliminate 80% of validation errors** (P0-R1: Node type normalization)
2. **Fix the majority of TypeError failures** (P0-R2: Null-safety audit)
3. **Replace inferior tool with superior alternative** (P0-R3: Template-based configs + remove get_node_for_task)

**Expected Overall Impact:**
- Error rate: 5-10% → <2%
- Configuration examples: 31 hardcoded → 2,000+ real templates
- Query performance: 30-60ms → <1ms (30-60x faster)
- User experience: Significant improvement across all tools
- Support burden: Reduced by 50%+

**Key Innovation (P0-R3):**
- Pre-extraction delivers 30-60x performance improvement
- 2,646 real templates provide richer context than hardcoded tasks
- Breaking change justified by superior replacement
- Database increase: Only +513 KB for 2,625 configurations

The implementation is well-architected, delivers exceptional value, and sets up future enhancements.

---

**Next Steps:**

1. ✅ Review implementation plan with team (COMPLETED)
2. ✅ Finalize architectural decisions (COMPLETED - pre-extraction chosen)
3. ✅ Create feature branch: `feature/p0-priorities-fixes` (COMPLETED)
4. ✅ **P0-R1**: Auto-Normalize Node Type Prefixes (COMPLETED - commit ed7de10)
5. ⏳ **P0-R2**: Complete Null-Safety Audit (PENDING)
6. ⏳ **P0-R3**: Pre-extract Template Configs + Remove get_node_for_task (PENDING)
7. ⏳ Deploy v2.15.0 with monitoring and telemetry analysis

**Target Release:** v2.15.0 (estimated 1.5 weeks remaining)


```

--------------------------------------------------------------------------------
/docs/local/DEEP_DIVE_ANALYSIS_2025-10-02.md:
--------------------------------------------------------------------------------

```markdown
# **N8N-MCP DEEP DIVE ANALYSIS**
## **Usage Patterns & Refactoring Recommendations**

**Analysis Period:** September 26 - October 2, 2025 (6 days)
**Data Volume:** 212,375 events | 5,751 workflows | 2,119 unique users
**Database:** Supabase telemetry with 15 analytical views
**Analyst:** Claude Code with Supabase MCP integration
**Date:** October 2, 2025

---

## **EXECUTIVE SUMMARY**

n8n-mcp has achieved **strong adoption** with 2,119 users generating 212K+ events in 6 days. The system demonstrates **excellent reliability** (96-100% success rates for most tools) but has **critical pain points** that are blocking users and degrading the AI agent experience. The upcoming refactor should focus on:

1. **Fixing the "node type prefix" validation catastrophe** (5,000+ validation errors from a single root cause)
2. **Resolving TypeError issues** in node information tools (1,000+ failures affecting 10% of calls)
3. **Streamlining the workflow update experience** (iterative updates dominate usage)
4. **Improving node discovery** (search is the #2 most-used tool but has UX gaps)
5. **Optimizing for power users** who drive 60% of activity

**Key Metrics:**
- **Overall Success Rate:** 96-98% across all user segments
- **Daily Event Growth:** 16K → 40K events (2.5x growth in 3 days)
- **Power User Concentration:** Top 3% of users generate 27% of events
- **Most Used Tools:** update_partial_workflow (10,177), search_nodes (8,839), create_workflow (6,046)
- **Critical Failure Rates:** get_node_for_task (28%), get_node_info (18%), get_node_essentials (10%)

---

## **TABLE OF CONTENTS**

1. [Tool Performance Analysis](#1-tool-performance-analysis)
2. [Validation Catastrophe](#2-validation-catastrophe)
3. [Usage Patterns & User Segmentation](#3-usage-patterns--user-segmentation)
4. [Tool Sequence Analysis](#4-tool-sequence-analysis)
5. [Workflow Creation Patterns](#5-workflow-creation-patterns)
6. [Platform & Version Distribution](#6-platform--version-distribution)
7. [Error Patterns & Root Causes](#7-error-patterns--root-causes)
8. [Prioritized Refactoring Recommendations](#8-prioritized-refactoring-recommendations)
9. [Architectural Recommendations](#9-architectural-recommendations)
10. [Telemetry Enhancements](#10-telemetry-enhancements)
11. [Specific Code Changes](#11-specific-code-changes)
12. [CHANGELOG Integration](#12-changelog-integration)
13. [Final Recommendations Summary](#13-final-recommendations-summary)

---

## **1. TOOL PERFORMANCE ANALYSIS**

### **1.1 Success Rate Tiers**

**EXCELLENT (95-100% success):**
- ✅ `n8n_update_partial_workflow` - 10,177 calls, 98.7% success, 846 users
- ✅ `search_nodes` - 8,839 calls, 99.8% success, 1,283 users
- ✅ `n8n_create_workflow` - 6,046 calls, 96.1% success, 1,305 users
- ✅ `n8n_validate_workflow` - 3,222 calls, 99.8% success, 597 users
- ✅ `n8n_get_workflow` - 3,368 calls, 99.8% success, 790 users
- ✅ `n8n_update_full_workflow` - 2,640 calls, 99.4% success, 486 users
- ✅ `tools_documentation` - 1,886 calls, 100% success, 879 users
- ✅ `validate_workflow` - 1,667 calls, 95.4% success, 472 users
- ✅ All n8n workflow management tools (list/delete/health) - 100% success

**GOOD (80-95% success):**
- ⚠️ `get_node_essentials` - 4,909 calls, **90.2% success**, 921 users (**9.8% failure**)
- ⚠️ `get_node_documentation` - 1,919 calls, 92.9% success, 657 users (**7.1% failure**)
- ⚠️ `validate_node_operation` - 998 calls, 88.6% success, 240 users (**11.4% failure**)
- ⚠️ `list_ai_tools` - 234 calls, 84.2% success, 184 users (**15.8% failure**)
- ⚠️ `get_node_info` - 1,988 calls, **82.3% success**, 677 users (**17.7% failure**)

**POOR (50-80% success):**
- 🔴 `get_node_for_task` - 392 calls, **72.2% success**, 197 users (**27.8% failure**)

### **1.2 Performance Metrics**

**Ultra-Fast (<10ms avg):**
- `get_node_essentials`: 3.27ms avg (median: 1ms)
- `get_node_info`: 4.78ms avg (median: 1ms)
- `get_node_documentation`: 2.16ms avg (median: 1ms)
- `tools_documentation`: 3.42ms avg (median: 1ms)
- `validate_node_minimal`: 1.79ms avg (median: 1ms)

**Fast (10-100ms avg):**
- `search_nodes`: 20.47ms avg (median: 5ms, p95: 84ms)
- `validate_workflow`: 31.59ms avg (median: 12ms, p95: 103ms)
- `list_nodes`: 41.86ms avg (median: 11ms, p95: 196ms)

**Acceptable (100-500ms avg):**
- `n8n_get_workflow`: 248.79ms avg (median: 111ms, p95: 830ms)
- `n8n_validate_workflow`: 229.37ms avg (median: 106ms, p95: 722ms)
- `n8n_update_full_workflow`: 302.70ms avg (median: 119ms, p95: 1,069ms)
- `n8n_delete_workflow`: 308.85ms avg (median: 166ms, p95: 950ms)
- `n8n_create_workflow`: 333.37ms avg (median: 85ms, p95: 1,251ms)
- `n8n_list_workflows`: 476.05ms avg (median: 231ms, p95: 1,465ms)
- `n8n_autofix_workflow`: 486.49ms avg (median: 174ms, p95: 1,152ms)

**Slow (>500ms avg):**
- `n8n_get_execution`: 670.35ms avg (median: 121ms, p95: 1,166ms)
- `n8n_trigger_webhook_workflow`: 1,884.67ms avg (median: 157ms, p95: 4,865ms)

### **1.3 Critical Findings**

**FINDING #1: Node information tools have systematic TypeError issues**
- `get_node_essentials`: 483 failures (10% of calls)
- `get_node_info`: 352 failures (18% of calls)
- `get_node_documentation`: 136 failures (7% of calls)
- **Root cause**: Accessing undefined properties on node objects (from CHANGELOG 2.14.0 fix)
- **Impact**: AI agents cannot get basic node information, blocking workflow creation
- **Evidence**: 400+ TypeError occurrences from error logs

**FINDING #2: Task-based node discovery is failing 28% of the time**
- `get_node_for_task` has the worst success rate (72%)
- **Impact**: When AI agents ask "which node should I use for X task?", they fail 1 in 4 times
- **Likely cause**: Limited task library or poor task-to-node mapping
- **Usage pattern**: 392 calls, 197 users → high demand but low reliability

**FINDING #3: Performance is excellent across the board**
- Node lookup tools: <5ms average (ultra-fast SQLite queries)
- Search operations: ~20ms average (efficient FTS5 indexing)
- Network operations (n8n API): 200-500ms average (acceptable for HTTP calls)
- Webhook triggers: 1,885ms average (expected for workflow execution)
- **Conclusion**: Performance is NOT a bottleneck; reliability is

**FINDING #4: Workflow management tools have perfect reliability**
- `n8n_list_workflows`: 100% success (1,489 calls)
- `n8n_health_check`: 100% success (1,304 calls)
- `n8n_list_executions`: 100% success (1,297 calls)
- `n8n_delete_workflow`: 100% success (1,230 calls)
- **Takeaway**: The n8n API integration layer is rock-solid

---

## **2. VALIDATION CATASTROPHE**

### **2.1 The "Node Type Prefix" Disaster**

**CRITICAL ISSUE:** 5,000+ validation errors from a single root cause

```
Error: Invalid node type: "nodes-base.set". Use "n8n-nodes-base.set" instead.
```

**Breakdown by error type:**
1. **4,800 occurrences**: "Invalid node type" prefix errors across Node0-Node19
   - Pattern: `nodes-base.X` instead of `n8n-nodes-base.X`
   - Affected nodes: ALL node types (Set, HTTP Request, Code, etc.)
   - **Impact**: 1 affected user with systematic errors across entire workflow

2. **2,500 occurrences**: "Multi-node workflow has no connections"
   - Likely same 2 users testing/debugging
   - Message: "Multi-node workflow has no connections. Nodes must be connected..."
   - **Pattern**: Valid validation but high repetition suggests test loops

3. **58 occurrences**: "Single-node workflows are only valid for webhook endpoints"
   - 42 affected users
   - **This is good validation** - appropriate message

4. **22 occurrences**: Duplicate node ID: "undefined"
   - 5 affected users
   - **Likely bug**: Nodes being created without IDs

### **2.2 Root Cause Analysis**

**Why AI agents produce `nodes-base.X` instead of `n8n-nodes-base.X`:**

1. **Token efficiency**: LLMs may abbreviate to save tokens
2. **Pattern learning**: AI may see shortened versions in docs/examples
3. **Natural language**: "nodes-base" is more concise than "n8n-nodes-base"
4. **Inconsistency**: Some tools may accept both formats, creating confusion

**Why the system doesn't auto-correct:**

From CHANGELOG 2.14.2:
> "Fixed validation false positives for Google Drive nodes with 'fileFolder' resource
> - Added node type normalization to handle both `n8n-nodes-base.` and `nodes-base.` prefixes correctly"

**Analysis**: A fix was attempted in 2.14.2, but it's **incomplete or not applied universally**. The normalization logic exists but isn't being called in all validation paths.

### **2.3 Impact Assessment**

**User Experience:**
- **Frustration**: AI agents receive validation errors requiring manual intervention
- **Token waste**: Multiple retry attempts with failed validations
- **Broken flow**: Interrupts the natural workflow creation process

**Quantitative Impact:**
- **80% of all validation errors** stem from this single issue
- **Affects ALL node types**, not specific to certain nodes
- **Systematic pattern**: Once a user hits this, they hit it repeatedly

**Why This Is Critical:**
- Easy to fix (normalization helper already exists)
- Massive impact (eliminates 4,800+ errors)
- Improves AI agent experience significantly

### **2.4 Other Validation Issues**

**Connection Validation:**
- "Connection uses node ID instead of node name" - 1 occurrence
- Good error message with clear guidance
- Not a systemic issue

**Node Configuration:**
- Various property-specific validation errors (low frequency)
- Generally well-handled with actionable messages

---

## **3. USAGE PATTERNS & USER SEGMENTATION**

### **3.1 User Distribution**

| Segment | Users | % | Events | Avg Events | Workflows | Success Rate |
|---------|-------|---|--------|------------|-----------|--------------|
| **Power Users (1000+)** | 12 | 0.6% | 25,346 | 2,112 | 33 | 97.1% |
| **Heavy Users (500-999)** | 47 | 2.2% | 31,608 | 673 | 18 | 98.0% |
| **Regular Users (100-499)** | 516 | 24.3% | 102,931 | 199 | 7 | 96.5% |
| **Active Users (20-99)** | 919 | 43.4% | 47,768 | 52 | 2 | 97.0% |
| **Casual Users (<20)** | 625 | 29.5% | 4,958 | 8 | 1 | 97.6% |
| **TOTAL** | 2,119 | 100% | 212,611 | 100 | - | 97.0% |

### **3.2 Key Insights**

**INSIGHT #1: Extreme power law distribution**
- **Top 59 users (3%)** generate **27% of all events** (57K events)
- **Top 575 users (27%)** generate **76% of all events** (160K events)
- **Bottom 625 users (30%)** generate only **2% of events** (5K events)

**Implications:**
- Optimize for power users → 3x impact per feature
- Onboarding is good (casual users have 97.6% success rate)
- Need enterprise features for heavy users (monitoring, analytics, team features)

**INSIGHT #2: Regular users (516) are the core audience**
- 103K events total (48% of all activity)
- 7 workflows/user average (meaningful engagement)
- 96.5% success rate (room for improvement)
- **This is the growth segment** - convert to heavy users

**INSIGHT #3: Consistent success rates across segments**
- All segments: 96-98% success rate
- **Paradox**: Power users have LOWER success rate (97.1% vs 97.6% casual)
- **Explanation**: Power users attempt harder tasks → more edge cases
- **Opportunity**: Focus reliability improvements on advanced features

**INSIGHT #4: Workflow creation correlates with engagement**
- Power users: 33 workflows
- Heavy users: 18 workflows
- Regular users: 7 workflows
- Active users: 2 workflows
- **Metric**: Workflows created = proxy for value delivered

### **3.3 Daily Usage Trends**

| Date | Events | Users | Events/User | Growth |
|------|--------|-------|-------------|--------|
| Sep 26 | 16,334 | 958 | 17.0 | baseline |
| Sep 27 | 26,042 | 2,075 | 12.6 | +59% events |
| Sep 28 | 35,687 | 2,655 | 13.4 | +37% events |
| **Sep 29** | **40,361** | **3,039** | **13.3** | **+13% events (peak)** |
| Sep 30 | 39,833 | 3,319 | 12.0 | -1% events |
| Oct 1 | 39,854 | 3,528 | 11.3 | 0% events |
| Oct 2 | 14,500 | 1,057 | 13.7 | partial day |

**Growth Analysis:**
- **Rapid adoption**: 16K → 40K daily events (2.5x in 3 days)
- **Plateau**: Sep 29-Oct 1 stable at ~40K events/day
- **User growth**: 958 → 3,528 users (3.7x growth)
- **Efficiency**: Events per user declining (17 → 11) as user base broadens

**Interpretation:**
- System reached **initial scale** (~40K events/day, ~3K users/day)
- Now in **consolidation phase** - need to improve retention
- **Next growth phase** requires solving reliability issues (see P0 recommendations)

---

## **4. TOOL SEQUENCE ANALYSIS**

### **4.1 Most Common Patterns**

**Top 15 Tool Sequences (all show 300s = 5 min time delta):**

| Rank | Sequence | Count | Users | Pattern |
|------|----------|-------|-------|---------|
| 1 | `update_partial_workflow` → `update_partial_workflow` | 549 | 153 | Iterative refinement |
| 2 | `create_workflow` → `update_partial_workflow` | 297 | 118 | Create then refine |
| 3 | `update_partial_workflow` → `get_workflow` | 265 | 91 | Update then verify |
| 4 | `create_workflow` → `create_workflow` | 237 | 97 | Multiple attempts |
| 5 | `create_workflow` → `get_workflow` | 185 | 81 | Create then inspect |
| 6 | `create_workflow` → `search_nodes` | 166 | 72 | Create then discover |
| 7 | `validate_workflow` → `update_partial_workflow` | 161 | 63 | Validate then fix |
| 8 | `validate_workflow` → `validate_workflow` | 152 | 44 | Re-validation |
| 9 | `validate_workflow` → `get_workflow` | 134 | 53 | Validate then inspect |
| 10 | `update_partial_workflow` → `create_workflow` | 130 | 59 | Update then recreate |
| 11 | `get_workflow` → `update_partial_workflow` | 117 | 50 | Inspect then update |
| 12 | `update_full_workflow` → `update_partial_workflow` | 98 | 41 | Full to partial update |
| 13 | `update_partial_workflow` → `search_nodes` | 94 | 42 | Update then discover |
| 14 | `get_workflow` → `create_workflow` | 87 | 42 | Inspect then recreate |
| 15 | `create_workflow` → `tools_documentation` | 85 | 36 | Create then learn |

### **4.2 Critical Insights**

**INSIGHT #1: AI agents iterate heavily on workflows**
- **#1 sequence**: `update → update → update` (549 occurrences)
- **Pattern**: Create → Validate → Update → Validate → Update (feedback loop)
- **Workflow**:
  1. AI creates initial workflow
  2. Validates it (finds issues)
  3. Updates to fix issues
  4. Validates again (finds more issues)
  5. Continues iterating until success

**Implication**: The diff-based update system (v2.7.0) is **CRUCIAL** for token efficiency
- Without diff updates: Would need full workflow JSON each time (~10-50KB)
- With diff updates: Only send changed operations (~1-5KB)
- **Token savings**: 80-90% per update iteration

**INSIGHT #2: All transitions show 5-minute time deltas**
- **This is NOT actual elapsed time** - it's the telemetry "slow transition" threshold
- All sequences are marked as `is_slow_transition: true`
- **Actual insight**: AI agents take thinking time between tool calls (expected for LLMs)
- **Limitation**: Cannot determine real workflow creation speed with current data

**Recommendation**: Add fine-grained timing (see T1 in Telemetry Enhancements)

**INSIGHT #3: Node discovery happens AFTER workflow creation**
- `create_workflow → search_nodes` (166 occurrences)
- **Flow**:
  1. AI creates workflow with known nodes
  2. Realizes it needs additional nodes
  3. Searches for them
  4. Updates workflow with new nodes

**Opportunity**: Proactive node suggestions during creation (see P1-R5)

**INSIGHT #4: Validation drives updates**
- `validate_workflow → update_partial_workflow` (161 occurrences)
- `validate_workflow → validate_workflow` (152 occurrences)
- **Pattern**: Validation → Fix → Re-validate loop

**Quality**: This is GOOD behavior (AI agents using validation to improve)
**Optimization**: Better validation error messages → fewer iterations (see P1-R6)

### **4.3 Common Workflow Patterns**

**Pattern A: Create-Update-Validate Loop**
```
create_workflow → update_partial_workflow → validate_workflow → update_partial_workflow
```
- Most common for new workflows
- 3-5 iterations average before success

**Pattern B: Inspect-Modify-Deploy**
```
get_workflow → update_partial_workflow → validate_workflow → get_workflow
```
- Common for modifying existing workflows
- "Get" used to verify final state

**Pattern C: Search-Create-Refine**
```
search_nodes → create_workflow → update_partial_workflow → validate_workflow
```
- Discovery-driven workflow creation
- Users explore capabilities before creating

### **4.4 Tools Leading to Workflow Creation**

**Tools used within 5 minutes BEFORE workflow creation:**

| Tool | Occurrences | Users | Conversion Rate |
|------|-------------|-------|-----------------|
| `update_partial_workflow` | 6,271 | 547 | High |
| `search_nodes` | 6,099 | 901 | High |
| `get_node_essentials` | 3,361 | 649 | Medium |
| `create_workflow` | 2,810 | 742 | Medium (re-creation) |
| `get_workflow` | 2,057 | 512 | Medium |
| `validate_workflow` | 2,014 | 417 | Medium |
| `get_node_documentation` | 1,301 | 456 | Low |
| `tools_documentation` | 1,290 | 596 | Low |

**Interpretation:**
- **Discovery tools** (search_nodes, get_node_essentials) → high workflow creation
- **Documentation tools** → lower conversion (learning/exploring phase)
- **Workflow management** (update/validate) → iterative creation process

---

## **5. WORKFLOW CREATION PATTERNS**

### **5.1 Complexity Distribution**

| Complexity | Count | % | Avg Nodes | Median | Triggers | Webhooks |
|------------|-------|---|-----------|--------|----------|----------|
| **Simple** | 4,290 | 75% | 5.5 | 5 | 1,330 (31%) | 1,330 (31%) |
| **Medium** | 1,282 | 22% | 14.0 | 13 | 424 (33%) | 424 (33%) |
| **Complex** | 187 | 3% | 27.5 | 23 | 71 (38%) | 71 (38%) |
| **TOTAL** | 5,759 | 100% | 8.2 | 6 | 1,825 (32%) | 1,825 (32%) |

**Complexity Definitions:**
- **Simple**: ≤8 nodes
- **Medium**: 9-20 nodes
- **Complex**: 21+ nodes

### **5.2 Key Findings**

**FINDING #1: 75% of workflows are simple**
- AI agents prefer minimalism (5-6 nodes average)
- Small workflows are easier to reason about
- Faster creation and debugging
- **Implication**: Optimize for simple workflow creation experience

**FINDING #2: Complex workflows are rare but important**
- Only 3% of workflows (187 total)
- Average 27.5 nodes (large automation)
- 38% have triggers/webhooks (production use)
- **User profile**: Likely power users building production systems

**FINDING #3: Webhook usage is consistent across complexity**
- Simple: 31% have webhooks
- Medium: 33% have webhooks
- Complex: 38% have webhooks
- **Insight**: Webhooks are a fundamental pattern, not correlated with complexity

### **5.3 Most Popular Nodes**

**Top 20 Nodes by Workflow Count:**

| Rank | Node Type | Workflows | % | Users | Avg Workflow Size |
|------|-----------|-----------|---|-------|-------------------|
| 1 | `n8n-nodes-base.code` | 3,051 | 53% | 1,056 | 9.4 |
| 2 | `n8n-nodes-base.httpRequest` | 2,686 | 47% | 1,033 | 9.6 |
| 3 | `n8n-nodes-base.webhook` | 1,812 | 32% | 750 | 8.5 |
| 4 | `n8n-nodes-base.set` | 1,738 | 30% | 742 | 9.2 |
| 5 | `n8n-nodes-base.if` | 1,400 | 24% | 653 | 12.2 |
| 6 | `n8n-nodes-base.manualTrigger` | 1,391 | 24% | 590 | 7.9 |
| 7 | `n8n-nodes-base.respondToWebhook` | 1,113 | 19% | 484 | 8.7 |
| 8 | `@n8n/n8n-nodes-langchain.agent` | 884 | 15% | 403 | 9.7 |
| 9 | `n8n-nodes-base.scheduleTrigger` | 825 | 14% | 412 | 9.5 |
| 10 | `n8n-nodes-base.googleSheets` | 732 | 13% | 324 | 10.5 |
| 11 | `n8n-nodes-base.merge` | 599 | 10% | 311 | 13.8 |
| 12 | `@n8n/n8n-nodes-langchain.lmChatOpenAi` | 564 | 10% | 268 | 10.6 |
| 13 | `n8n-nodes-base.switch` | 534 | 9% | 262 | 13.7 |
| 14 | `n8n-nodes-base.openAi` | 486 | 8% | 261 | 10.1 |
| 15 | `n8n-nodes-base.splitInBatches` | 457 | 8% | 229 | 13.2 |
| 16 | `n8n-nodes-base.telegram` | 416 | 7% | 168 | 10.0 |
| 17 | `n8n-nodes-base.function` | 414 | 7% | 162 | 9.6 |
| 18 | `n8n-nodes-base.gmail` | 400 | 7% | 212 | 9.5 |
| 19 | `n8n-nodes-base.cron` | 380 | 7% | 182 | 9.2 |
| 20 | `n8n-nodes-base.noOp` | 322 | 6% | 174 | 10.9 |

### **5.4 Critical Insights**

**INSIGHT #1: Code node dominates (53% of workflows)**
- AI agents LOVE programmatic control
- Code node enables custom logic that other nodes can't provide
- **Implication**: Ensure code node documentation and examples are excellent

**INSIGHT #2: HTTP Request is in nearly half of workflows (47%)**
- Integration-heavy usage pattern
- Most workflows interact with external APIs
- **Synergy**: Code + HTTP Request (see co-occurrence analysis)

**INSIGHT #3: LangChain nodes show strong adoption (15%)**
- AI-on-AI workflows
- `langchain.agent` in 884 workflows
- `lmChatOpenAi` in 564 workflows
- **Trend**: AI-building-AI-workflows is a real use case

**INSIGHT #4: Average workflow size correlates with node type**
- Control flow nodes (if/switch): 12-14 nodes average (complex workflows)
- Data nodes (set/code): 9-10 nodes average (medium workflows)
- Trigger nodes (manualTrigger): 7-8 nodes average (simple workflows)

### **5.5 Node Co-occurrence Patterns**

**Top 20 Node Pairs:**

| Rank | Node 1 | Node 2 | Co-occurrence | Users | Avg Size | Pattern |
|------|--------|--------|---------------|-------|----------|---------|
| 1 | `code` | `httpRequest` | 1,646 | 686 | 10.4 | Data transformation + API |
| 2 | `webhook` | `respondToWebhook` | 1,043 | 452 | 8.8 | Standard webhook pattern |
| 3 | `code` | `webhook` | 1,008 | 442 | 9.6 | Custom webhook logic |
| 4 | `code` | `if` | 894 | 437 | 12.9 | Conditional with custom logic |
| 5 | `httpRequest` | `webhook` | 845 | 404 | 10.5 | Webhook-triggered API calls |
| 6 | `httpRequest` | `set` | 841 | 431 | 10.7 | API response processing |
| 7 | `httpRequest` | `if` | 815 | 420 | 13.4 | Conditional API logic |
| 8 | `code` | `manualTrigger` | 731 | 321 | 9.7 | Manual testing workflows |
| 9 | `httpRequest` | `manualTrigger` | 706 | 328 | 9.1 | Manual API testing |
| 10 | `code` | `set` | 677 | 339 | 11.6 | Data manipulation |
| 11 | `code` | `respondToWebhook` | 617 | 285 | 9.8 | Webhook responses |
| 12 | `code` | `scheduleTrigger` | 585 | 290 | 10.3 | Scheduled automation |
| 13 | `manualTrigger` | `set` | 569 | 290 | 8.6 | Simple manual workflows |
| 14 | `if` | `set` | 545 | 291 | 13.0 | Conditional data setting |
| 15 | `httpRequest` | `respondToWebhook` | 534 | 263 | 10.0 | API-based webhooks |
| 16 | `webhook` | `set` | 516 | 289 | 9.9 | Webhook data processing |
| 17 | `httpRequest` | `scheduleTrigger` | 511 | 270 | 10.4 | Scheduled API calls |
| 18 | `webhook` | `if` | 477 | 277 | 12.7 | Conditional webhooks |
| 19 | `code` | `googleSheets` | 475 | 212 | 11.4 | Sheets data processing |
| 20 | `agent` | `lmChatOpenAi` | 475 | 222 | 10.1 | AI agent workflows |

### **5.6 Pattern Recognition**

**Pattern A: The "Transform-and-Call" Pattern**
- `code + httpRequest` (1,646 workflows)
- **Flow**: Prepare data → Call API → Process response
- **Use cases**: Integration automation, data synchronization

**Pattern B: The "Webhook Handler" Pattern**
- `webhook + respondToWebhook` (1,043 workflows)
- **Flow**: Receive webhook → Process → Respond
- **Use cases**: Event-driven automation, API endpoints

**Pattern C: The "Conditional Integration" Pattern**
- `httpRequest + if + set` (combined ~2,000 workflows)
- **Flow**: Call API → Check response → Transform data
- **Use cases**: Smart integrations, error handling

**Pattern D: The "AI Agent" Pattern**
- `agent + lmChatOpenAi + memoryBufferWindow` (475 workflows)
- **Flow**: AI agent with memory and LLM
- **Use cases**: Conversational AI, intelligent automation

### **5.7 Node Usage in Complex Workflows**

**Top nodes in complex workflows (21+ nodes):**

| Rank | Node Type | Count | Avg Size |
|------|-----------|-------|----------|
| 1 | `code` | 139 | 26.7 |
| 2 | `httpRequest` | 125 | 27.6 |
| 3 | `if` | 111 | 27.4 |
| 4 | `set` | 87 | 28.0 |
| 5 | `switch` | 74 | 27.9 |
| 6 | `webhook` | 68 | 29.5 |
| 7 | `merge` | 62 | 27.1 |
| 8 | `splitInBatches` | 50 | 25.6 |

**Insight**: Complex workflows use the same core nodes, just more of them
- Control flow (if/switch) for complex logic
- Data manipulation (code/set) for transformations
- Integration (httpRequest) for external systems

---

## **6. PLATFORM & VERSION DISTRIBUTION**

### **6.1 Platform Breakdown**

**Top 20 Configurations:**

| Platform | Arch | Version | Sessions | Users | % |
|----------|------|---------|----------|-------|---|
| **Linux** | x64 | 2.14.0 | 1,488 | 242 | 34% |
| Linux | arm64 | 2.14.0 | 190 | 135 | 4% |
| **Windows** | x64 | 2.14.1 | 115 | 79 | 3% |
| Windows | x64 | 2.14.1 | 95 | 53 | 2% |
| **macOS** | arm64 | 2.14.1 | 77 | 51 | 2% |
| Windows | x64 | 2.14.1 | 70 | 41 | 2% |
| macOS | arm64 | 2.14.1 | 68 | 43 | 2% |
| Windows | x64 | 2.14.1 | 60 | 46 | 1% |
| Linux | x64 | 2.14.5 | 54 | 30 | 1% |
| macOS | arm64 | 2.14.1 | 51 | 26 | 1% |

**Aggregated by Platform:**
- **Linux**: ~40% (1,678 sessions) - Docker, cloud VMs, CI/CD
- **Windows**: ~25% (multiple versions)
- **macOS**: ~15% (mostly M1/M2 Macs)
- **Other/Unknown**: ~20%

### **6.2 Version Distribution**

| Version | Total Sessions | Estimated Users | Release Date |
|---------|----------------|-----------------|--------------|
| 2.14.0 | 1,678 | 377 | Sep 26 |
| 2.14.1 | 780+ | 500+ | Sep 26 |
| 2.14.2 | ~50 | ~40 | Sep 29 |
| 2.14.3 | ~30 | ~25 | Sep 29 |
| 2.14.4 | 29 | 27 | Sep 30 |
| 2.14.5 | 54 | 30 | Sep 30 |
| 2.14.6 | 74 | 56 | Oct 1 |

### **6.3 Critical Findings**

**FINDING #1: Majority stuck on 2.14.0 (37% of sessions)**
- 1,678 sessions on v2.14.0
- **Problem**: This version has known issues:
  - TypeError fixes incomplete (CHANGELOG 2.14.0)
  - Validation false positives (fixed in 2.14.2)
  - Template sanitization issues (fixed in 2.14.3)

**FINDING #2: Slow version adoption**
- Only 74 sessions on latest v2.14.6 (Oct 1 release)
- Only 54 sessions on v2.14.5 (Sep 30 release)
- **Gap**: Users not upgrading despite bug fixes

**FINDING #3: Linux dominates (40% of sessions)**
- Likely Docker deployments
- CI/CD integration
- Cloud VMs (AWS, GCP, Azure)
- **Implication**: Containerization is working well

**FINDING #4: Node.js version fragmentation**
- v22.20.0: Most common
- v22.19.0: Second most common
- v22.18.0, v22.17.0, v22.14.0: Long tail
- **No compatibility issues reported** (good)

### **6.4 Recommendations**

**R1: Version update notifications**
- Add update checker to MCP server
- Notify users of critical fixes
- Show CHANGELOG diff between versions

**R2: Docker image optimization**
- Pre-build for Linux x64 + arm64
- Multi-stage builds for smaller images
- Automatic version pinning

**R3: Breaking change policy**
- Clear migration guides for version updates
- Deprecation warnings before breaking changes
- Backward compatibility period (2 releases minimum)

---

## **7. ERROR PATTERNS & ROOT CAUSES**

### **7.1 TypeError Cascade in Node Tools**

**Error Distribution (from error logs):**

| Tool | TypeError Count | Affected Users | % Failure |
|------|-----------------|----------------|-----------|
| `get_node_essentials` | ~350 | 10+ | 9.8% |
| `get_node_info` | ~250 | 12+ | 17.7% |
| `get_node_documentation` | ~100 | 8+ | 7.1% |
| **TOTAL** | ~700 | ~30 | **varies** |

**From CHANGELOG 2.14.0:**
> "Fixed TypeErrors in `get_node_info`, `get_node_essentials`, and `get_node_documentation` tools that were affecting 50% of calls"
> "Added null safety checks for undefined node properties"

**Analysis:**
- Fix in 2.14.0 reduced failures from **50% → 10-18%**
- **Residual issues remain** (700+ errors in 6 days)
- **Root causes**:
  1. Incomplete null safety for edge cases
  2. Nodes with unusual/legacy structure
  3. Missing properties in database
  4. Nested property access without guards

**Example Error Pattern:**
```javascript
// Fails when node.properties.description is undefined
const description = node.properties.description.text;

// Should be:
const description = node?.properties?.description?.text ?? 'No description';
```

### **7.2 ValidationError in Workflow Creation**

**Pattern:**
- `n8n_create_workflow`: 237 failures (3.9% failure rate)
- Error type: `ValidationError`
- Context: `tool_execution`

**Root causes (from validation analysis):**
1. **Node type prefix errors** (80% of validation errors)
   - `nodes-base.X` vs `n8n-nodes-base.X`
   - See Section 2 for full analysis

2. **Missing connections** (10% of validation errors)
   - "Multi-node workflow has no connections"
   - Valid error, but could provide better guidance

3. **Duplicate node IDs** (5% of validation errors)
   - "Duplicate node ID: 'undefined'"
   - Likely bug in node generation

4. **Other validation issues** (5%)
   - Missing required properties
   - Invalid property values
   - Connection reference errors

### **7.3 Task Discovery Failures**

**Pattern:**
- `get_node_for_task`: 109 failures (27.8% failure rate)
- Error type: Not specified (likely "No matching task found")
- **Highest failure rate of any tool**

**Probable causes:**
1. **Limited task library** - Only ~30-40 predefined tasks
2. **No fuzzy matching** - Exact task name required
3. **Poor task descriptions** - AI agents can't guess correct task name
4. **Missing fallback** - Doesn't suggest alternatives

**Example failing queries (inferred):**
- "send email notification" (might need "email_send" task)
- "process json data" (might need "json_parse" task)
- "schedule workflow" (might need "cron_trigger" task)

### **7.4 Other Error Patterns**

**Low-frequency errors (<10 occurrences):**
- Tool not found errors (misspelled tool names)
- Invalid parameters (wrong types, missing required fields)
- Network timeouts (n8n API unavailable)
- Database errors (SQLite lock issues)

**These are expected in production and handled gracefully**

---

## **8. PRIORITIZED REFACTORING RECOMMENDATIONS**

### **P0 - CRITICAL (Fix Immediately)**

---

#### **P0-R1: Auto-normalize node type prefixes**

**Problem**: 4,800+ validation errors from `nodes-base.X` vs `n8n-nodes-base.X`

**Impact**:
- Eliminates **80% of all validation errors**
- Improves AI agent experience significantly
- Reduces token waste from retry attempts
- Unblocks hundreds of users

**Solution**:
```typescript
// src/services/workflow-validator.ts

export function normalizeNodeTypes(workflow: any): any {
  const normalized = { ...workflow };

  if (normalized.nodes) {
    normalized.nodes = normalized.nodes.map((node: any) => ({
      ...node,
      type: normalizeNodeType(node.type)
    }));
  }

  return normalized;
}

function normalizeNodeType(type: string): string {
  // Fix common AI-generated abbreviations
  const prefixMap: Record<string, string> = {
    'nodes-base.': 'n8n-nodes-base.',
    'nodes-langchain.': '@n8n/n8n-nodes-langchain.',
    'n8n-nodes-langchain.': '@n8n/n8n-nodes-langchain.'
  };

  for (const [short, full] of Object.entries(prefixMap)) {
    if (type.startsWith(short)) {
      return type.replace(short, full);
    }
  }

  return type;
}
```

**Apply in handlers**:
```typescript
// src/mcp/handlers-n8n-manager.ts

export async function handleCreateWorkflow(params: any): Promise<McpToolResponse> {
  // Normalize before validation
  const normalizedWorkflow = normalizeNodeTypes(params);

  const validation = await validateWorkflow(normalizedWorkflow);
  if (!validation.valid) {
    return { success: false, error: validation.errors };
  }

  // Use normalized workflow
  return await createWorkflow(normalizedWorkflow);
}

export async function handleUpdateFullWorkflow(params: any): Promise<McpToolResponse> {
  const normalizedWorkflow = normalizeNodeTypes(params);
  // ... rest of handler
}
```

**Testing**:
```typescript
// tests/unit/services/workflow-normalizer.test.ts

describe('normalizeNodeTypes', () => {
  it('should normalize nodes-base prefix', () => {
    const workflow = {
      nodes: [
        { id: '1', type: 'nodes-base.set', parameters: {} }
      ]
    };

    const result = normalizeNodeTypes(workflow);
    expect(result.nodes[0].type).toBe('n8n-nodes-base.set');
  });

  it('should handle already-normalized types', () => {
    const workflow = {
      nodes: [
        { id: '1', type: 'n8n-nodes-base.set', parameters: {} }
      ]
    };

    const result = normalizeNodeTypes(workflow);
    expect(result.nodes[0].type).toBe('n8n-nodes-base.set');
  });

  it('should normalize langchain nodes', () => {
    const workflow = {
      nodes: [
        { id: '1', type: 'nodes-langchain.agent', parameters: {} }
      ]
    };

    const result = normalizeNodeTypes(workflow);
    expect(result.nodes[0].type).toBe('@n8n/n8n-nodes-langchain.agent');
  });
});
```

**Effort**: 2-4 hours
**Risk**: Low (only adds normalization, doesn't change validation logic)
**Files**:
- `src/services/workflow-validator.ts` (new helper)
- `src/mcp/handlers-n8n-manager.ts` (apply in handlers)
- `tests/unit/services/workflow-normalizer.test.ts` (new tests)

---

#### **P0-R2: Complete null-safety audit of node information tools**

**Problem**: 10-18% failure rate for `get_node_essentials`, `get_node_info`, `get_node_documentation`

**Impact**:
- Reduce TypeError failures from **10-18% → <1%**
- Improve reliability of most-used tools
- Prevent AI agent blocking on node discovery

**Solution**: Comprehensive null-safety refactor

**Step 1: Update repository methods**
```typescript
// src/database/node-repository.ts

export class NodeRepository {
  getNodeEssentials(nodeType: string): NodeEssentials | null {
    try {
      const node = this.db.prepare(`
        SELECT * FROM nodes WHERE type = ?
      `).get(nodeType);

      if (!node) {
        return null;
      }

      // Safe property access with defaults
      return {
        type: node.type ?? 'unknown',
        displayName: node.displayName ?? node.name ?? 'Unknown Node',
        description: this.extractDescription(node),
        category: node.category ?? 'Uncategorized',
        icon: node.icon ?? 'fa:question',
        inputs: this.parseJSON(node.inputs, []),
        outputs: this.parseJSON(node.outputs, []),
        properties: this.extractEssentialProperties(node)
      };
    } catch (error) {
      this.logger.error('Error getting node essentials', { nodeType, error });
      return null;
    }
  }

  private extractDescription(node: any): string {
    // Try multiple possible locations for description
    if (node.description) return node.description;
    if (node.properties?.description?.text) return node.properties.description.text;
    if (node.properties?.description) return node.properties.description;
    if (node.subtitle) return node.subtitle;
    return 'No description available';
  }

  private parseJSON<T>(value: any, defaultValue: T): T {
    if (!value) return defaultValue;
    try {
      return typeof value === 'string' ? JSON.parse(value) : value;
    } catch {
      return defaultValue;
    }
  }

  private extractEssentialProperties(node: any): any[] {
    try {
      const props = this.parseJSON(node.properties, []);
      return props.map((prop: any) => ({
        name: prop.name ?? 'unknown',
        displayName: prop.displayName ?? prop.name ?? 'Unknown',
        type: prop.type ?? 'string',
        required: prop.required ?? false,
        default: prop.default ?? null,
        description: prop.description ?? ''
      }));
    } catch {
      return [];
    }
  }
}
```

**Step 2: Update handlers with error handling**
```typescript
// src/mcp/handlers.ts

export async function handleGetNodeEssentials(params: { nodeType: string }): Promise<McpToolResponse> {
  const { nodeType } = params;

  // Validate input
  if (!nodeType || typeof nodeType !== 'string') {
    return {
      success: false,
      error: 'Invalid nodeType parameter'
    };
  }

  try {
    const essentials = await nodeRepository.getNodeEssentials(nodeType);

    if (!essentials) {
      return {
        success: false,
        error: `Node type "${nodeType}" not found. Use search_nodes to find available nodes.`
      };
    }

    return {
      success: true,
      data: essentials
    };
  } catch (error) {
    return {
      success: false,
      error: `Failed to get node essentials: ${error.message}`
    };
  }
}
```

**Step 3: Add comprehensive tests**
```typescript
// tests/unit/database/node-repository.test.ts

describe('NodeRepository - Null Safety', () => {
  it('should handle node with missing description', () => {
    const node = { type: 'test.node', name: 'Test' };
    db.prepare('INSERT INTO nodes VALUES (?, ?, NULL)').run(node.type, node.name);

    const result = repository.getNodeEssentials('test.node');
    expect(result).not.toBeNull();
    expect(result.description).toBe('No description available');
  });

  it('should handle node with malformed JSON properties', () => {
    const node = { type: 'test.node', properties: 'invalid json' };
    db.prepare('INSERT INTO nodes VALUES (?, ?, ?)').run(node.type, node.name, node.properties);

    const result = repository.getNodeEssentials('test.node');
    expect(result).not.toBeNull();
    expect(result.properties).toEqual([]);
  });

  it('should return null for non-existent node', () => {
    const result = repository.getNodeEssentials('non.existent');
    expect(result).toBeNull();
  });
});
```

**Effort**: 1 day (8 hours)
**Risk**: Medium (changes core repository methods, needs thorough testing)
**Files**:
- `src/database/node-repository.ts` (refactor)
- `src/mcp/handlers.ts` (update error handling)
- `tests/unit/database/node-repository.test.ts` (comprehensive tests)
- `tests/unit/mcp/handlers.test.ts` (update tests)

**Success Criteria**:
- `get_node_essentials` failure rate: 10% → <1%
- `get_node_info` failure rate: 18% → <1%
- `get_node_documentation` failure rate: 7% → <1%
- 100% test coverage for null cases

---

#### **P0-R3: Improve `get_node_for_task` success rate**

**Problem**: 27.8% failure rate (worst-performing tool)

**Impact**:
- Improve from **72% → 95%+ success rate**
- Enable AI agents to discover nodes by task description
- Reduce frustration when agents don't know exact node names

**Solution**: Multi-pronged enhancement

**Step 1: Expand task library**
```typescript
// src/services/task-templates.ts

export const TASK_LIBRARY = {
  // HTTP & API
  'http_request': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
  'api_call': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
  'make_http_request': { node: 'n8n-nodes-base.httpRequest', priority: 1 },
  'fetch_data': { node: 'n8n-nodes-base.httpRequest', priority: 2 },

  // Data transformation
  'transform_data': { node: 'n8n-nodes-base.code', priority: 1 },
  'process_json': { node: 'n8n-nodes-base.code', priority: 1 },
  'manipulate_data': { node: 'n8n-nodes-base.set', priority: 2 },
  'set_values': { node: 'n8n-nodes-base.set', priority: 1 },

  // Email
  'send_email': { node: 'n8n-nodes-base.emailSend', priority: 1 },
  'email_notification': { node: 'n8n-nodes-base.emailSend', priority: 1 },
  'receive_email': { node: 'n8n-nodes-base.emailReadImap', priority: 1 },

  // Webhooks
  'webhook': { node: 'n8n-nodes-base.webhook', priority: 1 },
  'receive_webhook': { node: 'n8n-nodes-base.webhook', priority: 1 },
  'respond_to_webhook': { node: 'n8n-nodes-base.respondToWebhook', priority: 1 },

  // ... expand to 100+ tasks
};
```

**Step 2: Add fuzzy matching**
```typescript
// src/services/discovery-service.ts

import Fuse from 'fuse.js';

export class DiscoveryService {
  private taskIndex: Fuse<TaskDefinition>;

  constructor() {
    // Build fuzzy search index
    this.taskIndex = new Fuse(Object.entries(TASK_LIBRARY), {
      keys: ['0'], // Task name
      threshold: 0.4, // Allow some typos
      distance: 100
    });
  }

  getNodeForTask(taskDescription: string): TaskMatch[] {
    // 1. Try exact match
    const exactMatch = TASK_LIBRARY[taskDescription.toLowerCase()];
    if (exactMatch) {
      return [{
        node: exactMatch.node,
        confidence: 1.0,
        reason: 'Exact task match'
      }];
    }

    // 2. Try fuzzy match
    const fuzzyMatches = this.taskIndex.search(taskDescription);
    if (fuzzyMatches.length > 0) {
      return fuzzyMatches.slice(0, 3).map(match => ({
        node: match.item[1].node,
        confidence: 1 - match.score,
        reason: `Similar to "${match.item[0]}"`
      }));
    }

    // 3. Fallback to keyword search in node descriptions
    return this.searchNodesByKeywords(taskDescription);
  }

  private searchNodesByKeywords(query: string): TaskMatch[] {
    // Use existing search_nodes functionality
    const results = nodeRepository.searchNodes(query, { limit: 3 });
    return results.map(node => ({
      node: node.type,
      confidence: 0.5,
      reason: `Found by keyword search: "${query}"`
    }));
  }
}
```

**Step 3: Return multiple suggestions**
```typescript
// src/mcp/handlers.ts

export async function handleGetNodeForTask(params: { task: string }): Promise<McpToolResponse> {
  const { task } = params;

  try {
    const matches = discoveryService.getNodeForTask(task);

    if (matches.length === 0) {
      return {
        success: false,
        error: `No node found for task "${task}". Try search_nodes with keywords instead.`,
        suggestions: [
          'Use search_nodes to explore available nodes',
          'Check list_tasks to see predefined task names'
        ]
      };
    }

    return {
      success: true,
      data: {
        primaryMatch: matches[0],
        alternativeMatches: matches.slice(1),
        totalMatches: matches.length
      }
    };
  } catch (error) {
    return {
      success: false,
      error: `Failed to find node for task: ${error.message}`
    };
  }
}
```

**Step 4: Testing**
```typescript
// tests/unit/services/discovery-service.test.ts

describe('DiscoveryService - Task Matching', () => {
  it('should find exact task match', () => {
    const result = service.getNodeForTask('send_email');
    expect(result[0].node).toBe('n8n-nodes-base.emailSend');
    expect(result[0].confidence).toBe(1.0);
  });

  it('should handle typos with fuzzy matching', () => {
    const result = service.getNodeForTask('send emial'); // typo
    expect(result[0].node).toBe('n8n-nodes-base.emailSend');
    expect(result[0].confidence).toBeGreaterThan(0.7);
  });

  it('should return multiple suggestions', () => {
    const result = service.getNodeForTask('process data');
    expect(result.length).toBeGreaterThan(1);
    expect(result).toContainEqual(
      expect.objectContaining({ node: 'n8n-nodes-base.code' })
    );
  });

  it('should fallback to keyword search', () => {
    const result = service.getNodeForTask('sheets manipulation');
    expect(result.some(r => r.node.includes('googleSheets'))).toBe(true);
  });
});
```

**Effort**: 3 days (24 hours)
- Day 1: Expand task library (100+ tasks)
- Day 2: Implement fuzzy matching
- Day 3: Testing and refinement

**Risk**: Low (enhances existing functionality)
**Dependencies**: `fuse.js` (fuzzy search library)
**Files**:
- `src/services/task-templates.ts` (expand library)
- `src/services/discovery-service.ts` (new service)
- `src/mcp/handlers.ts` (update handler)
- `tests/unit/services/discovery-service.test.ts` (comprehensive tests)

**Success Criteria**:
- `get_node_for_task` success rate: 72% → 95%
- Average confidence score: >0.8
- Multiple suggestions returned for ambiguous queries

### **Immediate Actions (This Week) - P0**

**1. Auto-normalize node type prefixes (P0-R1)**
- **Impact**: Eliminate 4,800 validation errors (80% of all errors)
- **Effort**: 2-4 hours
- **Files**: `workflow-validator.ts`, `handlers-n8n-manager.ts`
- **ROI**: ⭐⭐⭐⭐⭐ (Massive impact, minimal effort)

**2. Complete null-safety audit (P0-R2)**
- **Impact**: Fix 10-18% TypeError failures
- **Effort**: 1 day (8 hours)
- **Files**: `node-repository.ts`, `handlers.ts`
- **ROI**: ⭐⭐⭐⭐⭐ (Critical reliability improvement)

**3. Expand task discovery library (P0-R3)**
- **Impact**: Improve 72% → 95% success rate
- **Effort**: 3 days (24 hours)
- **Files**: `task-templates.ts`, `discovery-service.ts`
- **ROI**: ⭐⭐⭐⭐ (High value for task-based workflows)

**Expected Overall Impact**:
- Error rate: 5-10% → <2%
- User satisfaction: Significant improvement
- Support burden: Reduced by 50%

```
Page 31/46FirstPrevNextLast