@path58/p58-n8n 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENT_INSTALL.md CHANGED
@@ -1,124 +1,127 @@
1
- # P58-n8n — Drop & Install
1
+ # p58-n8n — LLM Agent Installation Guide
2
2
 
3
- **For users:** Drop this file into any AI chat and say: **"Install this MCP server for me"**
3
+ > **🤖 ACTION REQUIRED:** You are reading this because a user wants you to install the **p58-n8n** MCP server. Follow the steps below in order. You have everything you need in this file — do NOT search the web for additional instructions. If the user dropped a repo URL or README, this is the authoritative installation guide.
4
4
 
5
- **For AI agents:** Follow the instructions in the AI AGENT section below.
5
+ > **Your job:** Detect the user's MCP client → find their n8n instance (if any) → write the config restart → verify. Minimize questions to the user — auto-discover what you can, only ask when you must (API key, n8n URL if not found).
6
6
 
7
7
  ---
8
8
 
9
- ## What you'll get
9
+ ## What is p58-n8n?
10
10
 
11
- P58-n8n gives your AI assistant deep n8n workflow knowledge 1,982 nodes, 40,179 operations, 26 auto-fix rules.
11
+ p58-n8n is an MCP server that gives LLMs the ability to validate, build, deploy, and manage n8n workflows. It provides 35 tools organized in tiers:
12
12
 
13
- | Tool | What it does |
14
- |------|-------------|
15
- | `validate_workflow` | Run L1-L6 validation on workflow JSON |
16
- | `get_operation_schema` | Get exact parameter requirements for any operation |
17
- | `check_parameter` | Validate a parameter value with typo detection |
18
- | `suggest_fix` | Get fix suggestions for validation issues |
19
- | `list_nodes` | Browse and search 1,982 n8n nodes |
20
- | `list_operations` | List all operations for a node type |
21
- | `get_node_info` | Get comprehensive node metadata |
22
- | `find_similar_pattern` | Search 9,000+ validated workflows |
13
+ - **Tier 1 (offline):** `validate_workflow`, `list_nodes`, `get_operation_schema`, `suggest_fix`, `check_parameter` — work immediately, no env vars needed
14
+ - **Tier 2-7 (require n8n):** `build_workflow`, `list_credentials`, `activate_workflow`, `execute_workflow`, `test_workflow`, `plan_workflow`, etc. — require connection to user's n8n instance
23
15
 
24
- ### Supported clients
16
+ ---
25
17
 
26
- | Client | Support | Transport |
27
- |--------|---------|-----------|
28
- | Claude Desktop (Chat + Cowork) | Primary | stdio |
29
- | Claude Code (CLI) | Primary | stdio |
30
- | Gemini CLI | Secondary | stdio |
31
- | ChatGPT Desktop | Not supported | Requires HTTP/SSE |
18
+ ## Installation Decision Tree
19
+
20
+ ```
21
+ Does the user have n8n running?
22
+ ├── YES Full install (N8N_API_URL + N8N_API_KEY)
23
+ │ All 34 tools work: validate, build, deploy, execute
24
+
25
+ └── NO / DON'T KNOW → Minimal install (no env vars)
26
+ Tier 1 tools only: validate, list, check params
27
+ User can add n8n config later
28
+ ```
32
29
 
33
30
  ---
34
31
 
35
- ## AI AGENT: Follow These Instructions
32
+ ## Step 1: Detect the MCP Client
36
33
 
37
- ### STEP 1 Detect Environment
34
+ Determine which AI client the user is using. Check for config files in this order:
38
35
 
39
- Determine your capabilities and the user's platform.
36
+ | Client | Config File Path | OS |
37
+ |--------|-----------------|-----|
38
+ | **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` | macOS |
39
+ | **Claude Desktop** | `%APPDATA%\Claude\claude_desktop_config.json` | Windows |
40
+ | **Claude Desktop** | `~/.config/Claude/claude_desktop_config.json` | Linux |
41
+ | **Claude Code** | Use `claude mcp add` CLI command | All |
42
+ | **Cursor** | `~/.cursor/mcp.json` | All |
43
+ | **Gemini CLI** | `~/.gemini/settings.json` or `~/.gemini/antigravity/mcp_config.json` | All |
44
+ | **VS Code (Copilot)** | `.vscode/mcp.json` in workspace | All |
40
45
 
41
- **Can you execute commands?**
42
- ```
43
- Can I run shell commands?
44
- ├─ YES (Claude Code, Cowork mode, Gemini CLI) → Go to STEP 2a (Auto-Install)
45
- └─ NO (Claude Desktop Chat-only) → Go to STEP 2b (Guided Install)
46
- ```
47
-
48
- **Detect platform:**
49
- ```
50
- What OS is the user on?
51
- ├─ macOS → Config paths use ~/Library/Application Support/
52
- ├─ Windows → Config paths use %APPDATA%\
53
- └─ Linux → Config paths use ~/.config/
54
- ```
46
+ **Detection method:** Check if these files exist. If multiple exist, ask the user which client they want to configure.
55
47
 
56
48
  ---
57
49
 
58
- ### STEP 2a Auto-Install (can run commands)
50
+ ## Step 2: Find the User's n8n Instance
59
51
 
60
- **Prerequisites verify first:**
52
+ Try these methods in order:
61
53
 
54
+ ### Method A: Check environment variables
62
55
  ```bash
63
- node --version
64
- # Must be v18.0.0 or higher. If not installed, tell the user to install from https://nodejs.org/
56
+ echo $N8N_API_URL
57
+ echo $N8N_API_BASE_URL
58
+ echo $N8N_HOST
65
59
  ```
66
60
 
67
- **Then install based on which client the user wants:**
68
-
69
- #### Claude Code
61
+ ### Method B: Probe common localhost ports
62
+ ```bash
63
+ # Standard n8n port
64
+ curl -s -o /dev/null -w "%{http_code}" http://localhost:5678/api/v1/workflows 2>/dev/null
65
+ # Returns 401 = n8n is running (auth required) ✅
66
+ # Returns 000 = n8n is not running at this address ❌
67
+ ```
70
68
 
71
- Run this single command:
69
+ ### Method C: Check Docker containers
70
+ ```bash
71
+ docker ps --filter "name=n8n" --format "{{.Ports}}" 2>/dev/null
72
+ # Example output: 0.0.0.0:5678->5678/tcp → n8n at localhost:5678
73
+ ```
72
74
 
75
+ ### Method D: Check running processes
73
76
  ```bash
74
- claude mcp add p58-n8n -- npx -y @path58/p58-n8n
77
+ ps aux | grep -i n8n | grep -v grep
75
78
  ```
76
79
 
77
- Done. Skip to STEP 3.
80
+ ### Method E: Ask the user
81
+ If none of the above work, ask: "What is the URL of your n8n instance? (e.g., http://localhost:5678 or https://n8n.example.com)"
78
82
 
79
- #### Claude Desktop (Cowork mode can write files)
83
+ **IMPORTANT:** The API URL must include the `/api/v1` suffix. Example: `http://localhost:5678/api/v1`
80
84
 
81
- Read the existing config file first, then MERGE the p58-n8n entry. NEVER overwrite the entire file.
85
+ ---
82
86
 
83
- **Config file paths:**
84
- - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
85
- - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
86
- - Linux: `~/.config/Claude/claude_desktop_config.json`
87
+ ## Step 3: Get the n8n API Key
87
88
 
88
- **If file exists:** Read it, parse the JSON, add this entry inside `mcpServers`:
89
+ The API key cannot be auto-discovered. The user must provide it or create one.
89
90
 
90
- ```json
91
- "p58-n8n": {
92
- "command": "npx",
93
- "args": ["-y", "@path58/p58-n8n"]
94
- }
95
- ```
91
+ **Instructions to give the user:**
92
+ 1. Open n8n in your browser (the URL from Step 2, without `/api/v1`)
93
+ 2. Go to **Settings → API Keys** (or **Settings → n8n API**)
94
+ 3. Click **Create an API key**
95
+ 4. Copy the key — it starts with `eyJ...` (JWT format)
96
+ 5. Share it with me so I can add it to your config
97
+
98
+ **If the user can't find API Keys in Settings:** They may be on n8n Community Edition < 0.225.0 or n8n Cloud with API disabled. API key management requires admin access.
99
+
100
+ ---
96
101
 
97
- **If file doesn't exist:** Create it with:
102
+ ## Step 4: Write the Configuration
98
103
 
104
+ ### For Claude Desktop / Cursor / Gemini CLI / VS Code (JSON config)
105
+
106
+ Read the existing config file, then add p58-n8n inside the `mcpServers` object. Do NOT overwrite existing MCP servers.
107
+
108
+ **Full config (with n8n):**
99
109
  ```json
100
110
  {
101
111
  "mcpServers": {
102
112
  "p58-n8n": {
103
113
  "command": "npx",
104
- "args": ["-y", "@path58/p58-n8n"]
114
+ "args": ["-y", "@path58/p58-n8n"],
115
+ "env": {
116
+ "N8N_API_URL": "http://localhost:5678/api/v1",
117
+ "N8N_API_KEY": "<paste-api-key-here>"
118
+ }
105
119
  }
106
120
  }
107
121
  }
108
122
  ```
109
123
 
110
- Tell the user to restart Claude Desktop.
111
-
112
- #### Gemini CLI
113
-
114
- There is NO `gemini mcp add` command. Edit the config file directly.
115
-
116
- **Config path:** `~/.gemini/settings.json` (user-level) or `.gemini/settings.json` (project-level)
117
-
118
- **If file exists:** Read it, parse JSON, add the `p58-n8n` entry inside `mcpServers`.
119
-
120
- **If file doesn't exist:** Create it with:
121
-
124
+ **Minimal config (validation only, no n8n needed):**
122
125
  ```json
123
126
  {
124
127
  "mcpServers": {
@@ -130,94 +133,103 @@ There is NO `gemini mcp add` command. Edit the config file directly.
130
133
  }
131
134
  ```
132
135
 
133
- ---
136
+ ### For Claude Code (CLI)
134
137
 
135
- ### STEP 2b — Guided Install (chat-only)
138
+ **Full config:**
139
+ ```bash
140
+ claude mcp add p58-n8n \
141
+ -e N8N_API_URL=http://localhost:5678/api/v1 \
142
+ -e N8N_API_KEY=<paste-api-key-here> \
143
+ -- npx -y @path58/p58-n8n
144
+ ```
136
145
 
137
- Ask the user which client they want to set up, then give them copy-paste instructions.
146
+ **Minimal config:**
147
+ ```bash
148
+ claude mcp add p58-n8n -- npx -y @path58/p58-n8n
149
+ ```
138
150
 
139
- **Ask:** "Which AI client do you want to use P58-n8n with?"
151
+ ---
140
152
 
141
- #### For Claude Desktop
153
+ ## Step 5: Restart the Client
142
154
 
143
- Tell the user:
155
+ The MCP server config is only read at startup. After writing the config:
144
156
 
145
- 1. Open your Claude Desktop config file:
146
- - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
147
- - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
148
- - **Linux:** `~/.config/Claude/claude_desktop_config.json`
157
+ | Client | Restart Method |
158
+ |--------|---------------|
159
+ | **Claude Desktop** | Quit completely (Cmd+Q on macOS), then reopen |
160
+ | **Claude Code** | Exit and restart the CLI session |
161
+ | **Cursor** | Restart Cursor (Cmd+Shift+P → Reload Window) |
162
+ | **Gemini CLI** | Exit and restart the CLI session, or use the MCP refresh command |
149
163
 
150
- 2. Add this inside the `mcpServers` object (create the file if it doesn't exist):
164
+ **CRITICAL:** On macOS, closing the window is NOT enough for Claude Desktop. The user must Cmd+Q to fully quit.
151
165
 
152
- ```json
153
- {
154
- "mcpServers": {
155
- "p58-n8n": {
156
- "command": "npx",
157
- "args": ["-y", "@path58/p58-n8n"]
158
- }
159
- }
160
- }
161
- ```
166
+ ---
162
167
 
163
- 3. Restart Claude Desktop.
168
+ ## Step 6: Verify Installation
164
169
 
165
- #### For Claude Code
170
+ After restart, run these verification steps:
166
171
 
167
- Tell the user to run:
172
+ ### Check 1: Tool availability
173
+ Ask: "List n8n nodes for sending email"
174
+ - **Expected:** The LLM calls `list_nodes` and returns results
175
+ - **If tools not visible:** Config file has syntax error or wrong path
168
176
 
169
- ```bash
170
- claude mcp add p58-n8n -- npx -y @path58/p58-n8n
171
- ```
177
+ ### Check 2: n8n connectivity (if configured)
178
+ Ask: "Check n8n server health"
179
+ - **Expected:** `connected: true` with server version
180
+ - **If `connected: false`:** Check N8N_API_URL — is n8n actually running at that address?
181
+ - **If `Authentication failed`:** Check N8N_API_KEY — is it valid?
172
182
 
173
- #### For Gemini CLI
183
+ ### Check 3: Full pipeline (if n8n connected)
184
+ Ask: "List my n8n credentials"
185
+ - **Expected:** Returns list of configured credentials
186
+ - **If error:** API key may be expired or n8n needs restart
174
187
 
175
- Tell the user:
188
+ ---
176
189
 
177
- 1. Open `~/.gemini/settings.json` (create if needed)
178
- 2. Add:
190
+ ## Environment Variables Reference
179
191
 
180
- ```json
181
- {
182
- "mcpServers": {
183
- "p58-n8n": {
184
- "command": "npx",
185
- "args": ["-y", "@path58/p58-n8n"]
186
- }
187
- }
188
- }
189
- ```
192
+ | Variable | Required? | Description | How to find |
193
+ |----------|-----------|-------------|-------------|
194
+ | `N8N_API_URL` | For Tier 2-7 tools | n8n instance API URL | See Step 2 above |
195
+ | `N8N_API_KEY` | For Tier 2-7 tools | n8n API authentication key | n8n → Settings → API Keys |
190
196
 
191
- #### For ChatGPT Desktop
197
+ > **Note:** `N8N_API_BASE_URL` is accepted as a fallback for `N8N_API_URL`. If neither is set, defaults to `http://localhost:5678/api/v1`.
192
198
 
193
- Tell the user: **ChatGPT Desktop is not supported.** It requires HTTP/SSE transport for MCP servers, but P58-n8n uses stdio transport. This may be supported in a future version.
199
+ ### Variables NOT needed for standard installation
200
+
201
+ | Variable | Purpose | Who needs it |
202
+ |----------|---------|-------------|
203
+ | `P58_DATABASE_URL` | Extended catalog enrichment | Path58 internal / advanced users only |
204
+ | `NODE_ENV` | Logger behavior | Not needed (server handles this) |
205
+ | `NO_COLOR` | Disable ANSI colors | Not needed (server strips automatically since v0.2.2) |
194
206
 
195
207
  ---
196
208
 
197
- ### STEP 3 — Verify Installation
209
+ ## Troubleshooting
198
210
 
199
- After setup, test with this prompt:
211
+ | Symptom | Cause | Fix |
212
+ |---------|-------|-----|
213
+ | Tools not appearing | Config syntax error | Validate JSON (check trailing commas, unclosed braces) |
214
+ | Tools not appearing | Wrong config file path | Verify OS-specific path from Step 1 |
215
+ | "npx: command not found" | Node.js not installed | Install from https://nodejs.org/ |
216
+ | "Authentication failed" on deploy tools | N8N_API_KEY missing or invalid | Add API key to config, restart client |
217
+ | "Connection refused" on server_health | n8n not running at configured URL | Start n8n or fix N8N_API_URL |
218
+ | All tools timeout | Firewall blocking localhost | Check firewall / VPN settings |
219
+ | Server shows "failed" status | ANSI color issue (pre-v0.2.2) | Update to latest version: `npx -y @path58/p58-n8n@latest` |
200
220
 
201
- > "List available n8n nodes for email"
221
+ ---
202
222
 
203
- **Expected result:** The AI calls `list_nodes` and returns nodes like `n8n-nodes-base.gmail`, `n8n-nodes-base.emailSend`, etc.
223
+ ## Post-Install: What the User Can Do
204
224
 
205
- **If it doesn't work:**
225
+ Once installed, the user can ask their AI assistant to:
206
226
 
207
- ```
208
- Tools not appearing?
209
- ├─ Config file in wrong location → Check OS-specific paths above
210
- ├─ Invalid JSON syntax → Validate with: cat <path> | python3 -m json.tool
211
- ├─ Client not restarted → Close and reopen the AI client
212
- ├─ npx not found → Install Node.js 18+ from https://nodejs.org/
213
- └─ Permission error → Try: sudo npm install -g @path58/p58-n8n
214
-
215
- Server starts but tools don't work?
216
- ├─ Database not accessible → Server needs network access to Supabase
217
- ├─ Timeout errors → Check internet connection
218
- └─ "Module not found" → Run: npm install -g @path58/p58-n8n (reinstall)
219
- ```
227
+ - **"Validate this n8n workflow JSON"** — Tier 1, works immediately
228
+ - **"What parameters does the Slack node need?"** — Tier 1, works immediately
229
+ - **"Build me a workflow that sends Slack when Gmail receives an email"** — Tier 2+, needs n8n
230
+ - **"List my n8n credentials"** Tier 2+, needs n8n
231
+ - **"Deploy and test this workflow"** Tier 2+, needs n8n
220
232
 
221
233
  ---
222
234
 
223
- **Package:** `@path58/p58-n8n` | **License:** MIT | **Built by [Path58](https://path58.com)**
235
+ **Package:** `@path58/p58-n8n` | **npm:** https://www.npmjs.com/package/@path58/p58-n8n | **Version:** 0.2.4+
package/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.4] - 2026-03-10
9
+
10
+ ### Added
11
+
12
+ - **Lazy initialization** — MCP server defers tool registration and fixer registry loading until after stdio handshake completes; eliminates cold-start timeouts on strict-timeout clients (Gemini CLI / Antigravity)
13
+ - **`setup_check` tool** — new Tier 7 diagnostic tool that validates server health, n8n connectivity, and database access in a single call; total tools now **35** across 7 tiers
14
+ - **Gemini CLI support** — installation guide and documentation updated with Gemini CLI / Antigravity configuration examples
15
+
16
+ ### Changed
17
+
18
+ - Documentation overhauled for v0.2.4: replaced Windsurf references with Gemini CLI throughout AGENT_INSTALL.md, README.md, and FRIEND_ONBOARDING.md
19
+ - Fixed broken `docs/INSTALLATION.md` links in README (file never existed) — now point to AGENT_INSTALL.md
20
+ - Standardized `N8N_API_URL` environment variable naming across all documentation
21
+ - Updated catalog counts in documentation: 1,545 nodes, 679 credentials, 35 tools
22
+
23
+ ### Fixed
24
+
25
+ - Server initialization no longer blocks the MCP handshake — clients with < 5s timeouts can now connect reliably
26
+ - Startup version banner now correctly reports v0.2.4
27
+ - **Friend & family UX hardening** — 5 catalog tool handlers now return `CATALOG_UNREACHABLE` or `DB_NOT_CONFIGURED` with setup guide URLs instead of opaque "internal error" when database issues occur
28
+ - DB pool auto-sizes for catalog-only users (max 3 connections, no keepAlive) — prevents resource exhaustion for friends without n8n
29
+ - Startup health check confirms database connectivity before accepting tool calls
30
+ - Shutdown race condition eliminated — in-flight request tracker waits up to 5s for active queries before pool disposal
31
+ - `makeDbNotConfiguredResponse` now includes `isError: true` flag so LLMs recognize the error
32
+ - `plan_workflow` description updated to note that `build_workflow` requires n8n API access
33
+
34
+ ## [0.2.3] - 2026-03-09
35
+
36
+ ### Fixed
37
+
38
+ - Internal release — build and bundle pipeline fixes
39
+
8
40
  ## [0.2.2] - 2026-03-09
9
41
 
10
42
  ### Fixed
@@ -98,8 +130,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
98
130
  - npm package published as `@path58/p58-n8n`
99
131
  - ESM module support with shebang for direct `npx` execution
100
132
 
101
- [0.2.2]: https://github.com/tsvika58/n8n-workflow-validator/releases/tag/v0.2.2
102
- [0.2.1]: https://github.com/tsvika58/n8n-workflow-validator/releases/tag/v0.2.1
103
- [0.2.0]: https://github.com/tsvika58/n8n-workflow-validator/releases/tag/v0.2.0
104
- [0.1.1]: https://github.com/tsvika58/n8n-workflow-validator/releases/tag/v0.1.1
105
- [0.1.0]: https://github.com/tsvika58/n8n-workflow-validator/releases/tag/v0.1.0
133
+ [0.2.4]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.2.4
134
+ [0.2.3]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.2.3
135
+ [0.2.2]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.2.2
136
+ [0.2.1]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.2.1
137
+ [0.2.0]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.2.0
138
+ [0.1.1]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.1.1
139
+ [0.1.0]: https://github.com/tsvika58/p58-n8n/releases/tag/v0.1.0
package/README.md CHANGED
@@ -4,10 +4,12 @@
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@path58/p58-n8n)](https://www.npmjs.com/package/@path58/p58-n8n)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
- [![Tests](https://github.com/tsvika58/n8n-workflow-validator/actions/workflows/ci.yml/badge.svg)](https://github.com/tsvika58/n8n-workflow-validator/actions/workflows/ci.yml)
7
+ [![Tests](https://github.com/tsvika58/p58-n8n/actions/workflows/ci.yml/badge.svg)](https://github.com/tsvika58/p58-n8n/actions/workflows/ci.yml)
8
8
 
9
9
  p58-n8n is an MCP server that gives your AI assistant deep knowledge of n8n — **1,545 nodes**, **12,619 operations**, **38,005 parameter rules** — so it can plan, build, validate, fix, and deploy workflows correctly. No manual iteration. No broken JSON.
10
10
 
11
+ > **🤖 AI Agent?** If you are an LLM assistant and a user asked you to install this MCP server, **stop here and read [`AGENT_INSTALL.md`](https://github.com/tsvika58/p58-n8n/blob/main/AGENT_INSTALL.md)** — it has the complete autonomous installation guide with client detection, n8n auto-discovery, config templates for all clients, and verification steps. Everything you need to install p58-n8n without asking the user unnecessary questions.
12
+
11
13
  ---
12
14
 
13
15
  ## Quick Start (< 2 minutes)
@@ -28,7 +30,10 @@ npm install -g @path58/p58-n8n
28
30
 
29
31
  **Claude Code** (one command):
30
32
  ```bash
31
- claude mcp add p58-n8n -- npx -y @path58/p58-n8n
33
+ claude mcp add p58-n8n \
34
+ -e N8N_API_URL=http://localhost:5678/api/v1 \
35
+ -e N8N_API_KEY=your-n8n-api-key \
36
+ -- npx -y @path58/p58-n8n
32
37
  ```
33
38
 
34
39
  **Claude Desktop** — add to `claude_desktop_config.json`:
@@ -39,16 +44,23 @@ claude mcp add p58-n8n -- npx -y @path58/p58-n8n
39
44
  "command": "npx",
40
45
  "args": ["-y", "@path58/p58-n8n"],
41
46
  "env": {
42
- "P58_DATABASE_URL": "your-supabase-connection-string"
47
+ "N8N_API_URL": "http://localhost:5678/api/v1",
48
+ "N8N_API_KEY": "your-n8n-api-key"
43
49
  }
44
50
  }
45
51
  }
46
52
  }
47
53
  ```
48
54
 
55
+ Get your API key from **n8n → Settings → API Keys**.
56
+
49
57
  Config file location: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows). Restart Claude Desktop after saving.
50
58
 
51
- **Cursor / Windsurf** see [docs/INSTALLATION.md](docs/INSTALLATION.md) for full multi-client setup.
59
+ > **Note:** Validation tools (`validate_workflow`, `list_nodes`, etc.) work immediately without any env vars. The `N8N_API_URL` and `N8N_API_KEY` are only needed for deploy, execute, and credential tools.
60
+
61
+ **Cursor / Gemini CLI** — same JSON format, add to your client's MCP config file. See [AGENT_INSTALL.md](https://github.com/tsvika58/p58-n8n/blob/main/AGENT_INSTALL.md) for all supported clients.
62
+
63
+ **LLM-assisted setup** — if you're an AI agent helping a user install p58-n8n, read [AGENT_INSTALL.md](https://github.com/tsvika58/p58-n8n/blob/main/AGENT_INSTALL.md) for the autonomous installation guide.
52
64
 
53
65
  ### 3. Try it
54
66
 
@@ -114,7 +126,7 @@ p58-n8n uses 80% less token context than n8n-mcp by serving structured catalog d
114
126
 
115
127
  ---
116
128
 
117
- ## 34 Tools in 7 Tiers
129
+ ## 35 Tools in 7 Tiers
118
130
 
119
131
  ### Tier 1 — Validation & Analysis
120
132
 
@@ -184,6 +196,7 @@ p58-n8n uses 80% less token context than n8n-mcp by serving structured catalog d
184
196
  | Tool | What it does |
185
197
  |------|-------------|
186
198
  | `collect_config` | Detect missing node configuration from your live n8n instance (covers 2,494 known gaps) |
199
+ | `setup_check` | Diagnostic report — server version, n8n connectivity, credential count, tool availability |
187
200
 
188
201
  Full reference with input/output schemas: [docs/TOOLS.md](docs/TOOLS.md)
189
202
 
@@ -223,11 +236,11 @@ p58-n8n will: call `get_credential_schema` for Slack → `create_credential` wit
223
236
 
224
237
  ## Installation
225
238
 
226
- See [docs/INSTALLATION.md](docs/INSTALLATION.md) for full setup instructions:
239
+ See [AGENT_INSTALL.md](https://github.com/tsvika58/p58-n8n/blob/main/AGENT_INSTALL.md) for full setup instructions:
227
240
 
228
241
  - Claude Desktop (macOS, Windows, Linux)
229
242
  - Claude Code (one-command setup)
230
- - Cursor and Windsurf
243
+ - Cursor and Gemini CLI
231
244
  - Global install vs npx
232
245
  - Troubleshooting
233
246
 
@@ -262,7 +275,7 @@ MIT — see [LICENSE](LICENSE) for details.
262
275
 
263
276
  p58-n8n is in **soft launch** (friends & family). Issues and feedback welcome:
264
277
 
265
- - **Bugs:** [GitHub Issues](https://github.com/tsvika58/n8n-workflow-validator/issues)
278
+ - **Bugs:** [GitHub Issues](https://github.com/tsvika58/p58-n8n/issues)
266
279
  - **Email:** tvagman@gmail.com
267
280
 
268
281
  ---
@@ -272,7 +285,7 @@ p58-n8n is in **soft launch** (friends & family). Issues and feedback welcome:
272
285
  p58-n8n runs as a local stdio MCP server. No cloud services required for basic use.
273
286
 
274
287
  ```
275
- AI Client (Claude / Cursor / Windsurf)
288
+ AI Client (Claude / Cursor / Gemini CLI)
276
289
  ↕ MCP Protocol (stdio)
277
290
  p58-n8n Server
278
291
  ├── Validation Engine (L1-L6, ~1.4s)
@@ -52,6 +52,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
52
52
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
53
53
  mod
54
54
  ));
55
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
55
56
 
56
57
  // node_modules/consola/dist/core.cjs
57
58
  var require_core = __commonJS({
@@ -3013,22 +3014,28 @@ function buildPoolOptions() {
3013
3014
  }
3014
3015
  function createPool(cfg) {
3015
3016
  const timeoutMs = getEnvNumber("DB_STATEMENT_TIMEOUT_MS", 3e4);
3017
+ const isCatalogOnly = !!(process.env.P58_DATABASE_URL || process.env.MCP_DATABASE_URL) && !process.env.N8N_API_KEY;
3016
3018
  const pool = new import_pg.Pool({
3017
3019
  host: cfg.host,
3018
3020
  port: resolvePoolPort(cfg),
3019
3021
  user: cfg.user,
3020
3022
  password: cfg.password,
3021
3023
  database: cfg.database,
3022
- max: getEnvNumber("VALIDATOR_DB_POOL_MAX", 10),
3023
- min: getEnvNumber("VALIDATOR_DB_POOL_MIN", 1),
3024
+ // Friends: 3 max (1 active + 2 burst). Full mode: 10.
3025
+ max: getEnvNumber("VALIDATOR_DB_POOL_MAX", isCatalogOnly ? 3 : 10),
3026
+ // Friends: 0 min — don't hold connections when idle. Full mode: 1.
3027
+ min: getEnvNumber("VALIDATOR_DB_POOL_MIN", isCatalogOnly ? 0 : 1),
3024
3028
  // allowExitOnIdle: true — prevents zombie processes when MCP session ends (RAG-4.35.5)
3025
- idleTimeoutMillis: 6e4,
3026
- connectionTimeoutMillis: 15e3,
3029
+ // Friends: 30s idle (release fast). Full mode: 60s.
3030
+ idleTimeoutMillis: isCatalogOnly ? 3e4 : 6e4,
3031
+ // Friends: 10s connect timeout (fail fast). Full mode: 15s.
3032
+ connectionTimeoutMillis: isCatalogOnly ? 1e4 : 15e3,
3027
3033
  statement_timeout: timeoutMs,
3028
3034
  options: buildPoolOptions(),
3029
3035
  allowExitOnIdle: true,
3030
- keepAlive: true,
3031
- keepAliveInitialDelayMillis: 1e4
3036
+ // Friends: no keepAlive (let connections close naturally). Full mode: keepAlive.
3037
+ keepAlive: !isCatalogOnly,
3038
+ ...isCatalogOnly ? {} : { keepAliveInitialDelayMillis: 1e4 }
3032
3039
  });
3033
3040
  pool.on("error", (err) => {
3034
3041
  console.warn(`[pg-pool] Idle connection error (non-fatal): ${err.message}`);
@@ -3040,6 +3047,24 @@ function getValidatorPool() {
3040
3047
  validatorPool = createPool(getValidatorDbConfig());
3041
3048
  return validatorPool;
3042
3049
  }
3050
+ async function warmSingleConnection(pool) {
3051
+ const client = await pool.connect();
3052
+ await client.query("SELECT 1");
3053
+ client.release();
3054
+ }
3055
+ async function warmValidatorPool() {
3056
+ if (poolWarmed)
3057
+ return;
3058
+ const pool = getValidatorPool();
3059
+ const minConns = getEnvNumber("VALIDATOR_DB_POOL_MIN", 1);
3060
+ try {
3061
+ for (let i = 0; i < minConns; i++)
3062
+ await warmSingleConnection(pool);
3063
+ poolWarmed = true;
3064
+ } catch (error) {
3065
+ console.warn("Validator pool warm-up failed, continuing with lazy connection creation:", error);
3066
+ }
3067
+ }
3043
3068
  async function validatorQuery(sql, params = []) {
3044
3069
  const client = await getValidatorPool().connect();
3045
3070
  const onClientError = (err) => {
@@ -3061,7 +3086,7 @@ async function shutdownValidatorPool() {
3061
3086
  validatorPool = null;
3062
3087
  }
3063
3088
  }
3064
- var import_pg, dotenv, path, import_url, import_connection, __filename, __dirname, PROJECT_ROOT, validatorPool;
3089
+ var import_pg, dotenv, path, import_url, import_connection, __filename, __dirname, PROJECT_ROOT, validatorPool, poolWarmed;
3065
3090
  var init_validatorPostgresClient = __esm({
3066
3091
  "dist/db/validatorPostgresClient.js"() {
3067
3092
  "use strict";
@@ -3076,6 +3101,7 @@ var init_validatorPostgresClient = __esm({
3076
3101
  dotenv.config({ path: path.resolve(PROJECT_ROOT, ".env.supabase") });
3077
3102
  dotenv.config({ path: path.resolve(PROJECT_ROOT, ".env") });
3078
3103
  validatorPool = null;
3104
+ poolWarmed = false;
3079
3105
  }
3080
3106
  });
3081
3107
 
@@ -18433,6 +18459,12 @@ var init_cached_catalog_adapter = __esm({
18433
18459
  });
18434
18460
 
18435
18461
  // dist/mcp/server.js
18462
+ var server_exports = {};
18463
+ __export(server_exports, {
18464
+ isServerInitialized: () => isServerInitialized,
18465
+ logStartupSummary: () => logStartupSummary
18466
+ });
18467
+ module.exports = __toCommonJS(server_exports);
18436
18468
  var import_server = require("@modelcontextprotocol/sdk/server/index.js");
18437
18469
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
18438
18470
  var import_types22 = require("@modelcontextprotocol/sdk/types.js");
@@ -18441,7 +18473,7 @@ var import_types22 = require("@modelcontextprotocol/sdk/types.js");
18441
18473
  var config = {
18442
18474
  // Server identity
18443
18475
  SERVER_NAME: "p58-n8n",
18444
- SERVER_VERSION: "0.2.2",
18476
+ SERVER_VERSION: "0.2.4",
18445
18477
  // Database configuration (from environment)
18446
18478
  SUPABASE_URL: process.env.SUPABASE_URL,
18447
18479
  SUPABASE_KEY: process.env.SUPABASE_KEY,
@@ -18727,6 +18759,7 @@ var collectConfigSchema = import_zod.z.object({
18727
18759
  config_requirements: import_zod.z.array(configRequirementItemSchema).optional().describe("Config requirements from plan_workflow response (preferred over workflow_json). Pass the configRequirements array directly from plan_workflow output."),
18728
18760
  user_responses: import_zod.z.record(import_zod.z.unknown()).optional().describe('User-provided values keyed by "nodeType:parameterName" (from question.id). Example: { "n8n-nodes-base.googleSheets:spreadsheetId": "1BxiMVs0..." }. Omit to get questions without providing values (first turn of multi-turn collection).')
18729
18761
  });
18762
+ var setupCheckSchema = import_zod.z.object({});
18730
18763
  var toolSchemas = {
18731
18764
  test_workflow: testWorkflowSchema,
18732
18765
  validate_workflow: validateWorkflowSchema,
@@ -18761,7 +18794,8 @@ var toolSchemas = {
18761
18794
  test_credential: testCredentialSchema,
18762
18795
  update_credential: updateCredentialSchema,
18763
18796
  delete_credential: deleteCredentialSchema,
18764
- collect_config: collectConfigSchema
18797
+ collect_config: collectConfigSchema,
18798
+ setup_check: setupCheckSchema
18765
18799
  };
18766
18800
 
18767
18801
  // dist/mcp/tools/validate.js
@@ -19171,6 +19205,30 @@ async function injectResponseMetadata(sessionId, toolName, response, executionSt
19171
19205
  return instrumented;
19172
19206
  }
19173
19207
 
19208
+ // dist/mcp/in-flight-tracker.js
19209
+ var inflightCount = 0;
19210
+ function incrementInflight() {
19211
+ inflightCount++;
19212
+ }
19213
+ function decrementInflight() {
19214
+ if (inflightCount > 0)
19215
+ inflightCount--;
19216
+ }
19217
+ function waitForInflightRequests(timeoutMs) {
19218
+ if (inflightCount === 0)
19219
+ return Promise.resolve();
19220
+ return new Promise((resolve2) => {
19221
+ const deadline = setTimeout(resolve2, timeoutMs);
19222
+ const poll = setInterval(() => {
19223
+ if (inflightCount <= 0) {
19224
+ clearInterval(poll);
19225
+ clearTimeout(deadline);
19226
+ resolve2();
19227
+ }
19228
+ }, 50);
19229
+ });
19230
+ }
19231
+
19174
19232
  // dist/validation/l1-structure.js
19175
19233
  async function validateL1Structure(workflowJson) {
19176
19234
  const startTime = performance.now();
@@ -30380,7 +30438,13 @@ var AutoFixerRegistry = class _AutoFixerRegistry {
30380
30438
  }
30381
30439
  }
30382
30440
  };
30383
- var fixerRegistry = new AutoFixerRegistry();
30441
+ var _fixerRegistry = null;
30442
+ function getFixerRegistry() {
30443
+ if (!_fixerRegistry) {
30444
+ _fixerRegistry = new AutoFixerRegistry();
30445
+ }
30446
+ return _fixerRegistry;
30447
+ }
30384
30448
 
30385
30449
  // node_modules/axios/lib/helpers/bind.js
30386
30450
  function bind(fn, thisArg) {
@@ -34878,7 +34942,7 @@ async function runAutofixOnWorkflow(workflowJson, issues) {
34878
34942
  const { applied: credApplied, changelog: credChangelog } = preAssignCredentials(workflow, issues);
34879
34943
  const errorIssues = issues.filter((i) => i.severity === "error");
34880
34944
  const problems = errorIssues.map(issueToValidationProblem);
34881
- const fixResult = await fixerRegistry.applyFixes(workflow, problems);
34945
+ const fixResult = await getFixerRegistry().applyFixes(workflow, problems);
34882
34946
  const fixChangelog = buildChangelog(fixResult.results);
34883
34947
  return {
34884
34948
  fixedWorkflow: fixResult.workflow,
@@ -35273,10 +35337,10 @@ How it works:
35273
35337
 
35274
35338
  Validation levels:
35275
35339
  - L1: JSON structure, required fields, duplicate node names
35276
- - L2: Node types exist in catalog (1,982 nodes)
35277
- - L3: Credential types valid (654 credentials) \u2014 includes available_credentials lookup
35278
- - L4: Connection patterns exist (6,900 rules)
35279
- - L5: Required parameters configured (35,143 params)
35340
+ - L2: Node types exist in catalog (1,545 nodes)
35341
+ - L3: Credential types valid (679 credentials) \u2014 includes available_credentials lookup
35342
+ - L4: Connection patterns exist (7,642 rules)
35343
+ - L5: Required parameters configured (38,005 params)
35280
35344
  - L6: Pattern validation (flow integrity, security, expressions)
35281
35345
 
35282
35346
  Returns detailed issues with severity, location, and suggested fixes.
@@ -35479,7 +35543,7 @@ var getOperationSchemaToolDefinition = {
35479
35543
  name: "get_operation_schema",
35480
35544
  description: `Get parameter requirements for a specific n8n node operation.
35481
35545
 
35482
- Returns the exact required and optional parameters from our 35,143 parameter catalog.
35546
+ Returns the exact required and optional parameters from our 38,005 parameter catalog.
35483
35547
  Use this to prevent parameter hallucination when generating n8n workflows.
35484
35548
 
35485
35549
  Examples:
@@ -36565,6 +36629,77 @@ Examples:
36565
36629
  }
36566
36630
  };
36567
36631
 
36632
+ // dist/mcp/tools/handlers/shared/n8n-guard.js
36633
+ var SETUP_GUIDE_URL = "https://github.com/tsvika58/p58-n8n/blob/main/docs/AGENT_INSTALL.md";
36634
+ var OFFLINE_TOOLS = /* @__PURE__ */ new Set([
36635
+ "validate_workflow",
36636
+ "get_operation_schema",
36637
+ "check_parameter",
36638
+ "suggest_fix",
36639
+ "list_operations",
36640
+ "list_nodes",
36641
+ "get_node_info",
36642
+ "find_similar_pattern",
36643
+ "get_session_metrics",
36644
+ "get_credential_schema",
36645
+ "setup_check"
36646
+ ]);
36647
+ function requiresN8nApiKey(toolName) {
36648
+ return !OFFLINE_TOOLS.has(toolName);
36649
+ }
36650
+ function makeN8nNotConfiguredError() {
36651
+ return {
36652
+ content: [
36653
+ {
36654
+ type: "text",
36655
+ text: JSON.stringify({
36656
+ error: `This tool requires n8n connection. Set N8N_API_URL and N8N_API_KEY in your MCP config. See: ${SETUP_GUIDE_URL}`
36657
+ })
36658
+ }
36659
+ ],
36660
+ isError: true
36661
+ };
36662
+ }
36663
+ function isDbConfigError(error) {
36664
+ const msg = error instanceof Error ? error.message : String(error);
36665
+ return msg.includes("Missing required validator DB environment variable");
36666
+ }
36667
+ function isDbConnectionError(error) {
36668
+ const msg = error instanceof Error ? error.message : String(error);
36669
+ return msg.includes("ECONNREFUSED") || msg.includes("ETIMEDOUT") || msg.includes("connect ETIMEDOUT") || msg.includes("after calling end on the pool") || msg.includes("Connection terminated") || msg.includes("getaddrinfo ENOTFOUND") || msg.includes("too many connections") || msg.includes("remaining connection slots");
36670
+ }
36671
+ function makeDbNotConfiguredResponse() {
36672
+ return {
36673
+ content: [
36674
+ {
36675
+ type: "text",
36676
+ text: JSON.stringify({
36677
+ error: "DB_NOT_CONFIGURED",
36678
+ message: "Catalog features require P58_DATABASE_URL. Set P58_DATABASE_URL in your MCP config to enable this tool.",
36679
+ setup_guide: SETUP_GUIDE_URL
36680
+ })
36681
+ }
36682
+ ],
36683
+ isError: true
36684
+ };
36685
+ }
36686
+ function makeDbConnectionErrorResponse() {
36687
+ return {
36688
+ content: [
36689
+ {
36690
+ type: "text",
36691
+ text: JSON.stringify({
36692
+ error: "CATALOG_UNREACHABLE",
36693
+ message: "Catalog database is unreachable. Verify your P58_DATABASE_URL is correct and the database server is accessible. If the problem persists, contact Tsvika.",
36694
+ hint: "Check: (1) connection string starts with postgresql://mcp_friend... (2) port is 6543 (transaction pooler) (3) network allows outbound to AWS eu-north-1",
36695
+ setup_guide: SETUP_GUIDE_URL
36696
+ })
36697
+ }
36698
+ ],
36699
+ isError: true
36700
+ };
36701
+ }
36702
+
36568
36703
  // dist/mcp/middleware/response-compression.js
36569
36704
  function selectFields(item, fields) {
36570
36705
  const result = {};
@@ -36684,8 +36819,11 @@ async function handleListOperations(args) {
36684
36819
  return toMCPResponse(response);
36685
36820
  } catch (error) {
36686
36821
  const originalError = error instanceof Error ? error : new Error(String(error));
36687
- const errorResponse = createInternalError(correlationId, originalError);
36688
- return toMCPResponse(errorResponse);
36822
+ if (isDbConfigError(originalError))
36823
+ return makeDbNotConfiguredResponse();
36824
+ if (isDbConnectionError(originalError))
36825
+ return makeDbConnectionErrorResponse();
36826
+ return toMCPResponse(createInternalError(correlationId, originalError));
36689
36827
  }
36690
36828
  }
36691
36829
  var listOperationsToolDefinition = {
@@ -36782,13 +36920,16 @@ async function handleListNodes(args) {
36782
36920
  return toMCPResponse(response);
36783
36921
  } catch (error) {
36784
36922
  const originalError = error instanceof Error ? error : new Error(String(error));
36785
- const errorResponse = createInternalError(correlationId, originalError);
36786
- return toMCPResponse(errorResponse);
36923
+ if (isDbConfigError(originalError))
36924
+ return makeDbNotConfiguredResponse();
36925
+ if (isDbConnectionError(originalError))
36926
+ return makeDbConnectionErrorResponse();
36927
+ return toMCPResponse(createInternalError(correlationId, originalError));
36787
36928
  }
36788
36929
  }
36789
36930
  var listNodesToolDefinition = {
36790
36931
  name: "list_nodes",
36791
- description: `List all available n8n nodes (1,982 total) with filtering and pagination.
36932
+ description: `List all available n8n nodes (1,545 total) with filtering and pagination.
36792
36933
 
36793
36934
  Use this to discover available nodes before generating workflows. The tool supports:
36794
36935
  - Pagination: Use limit (1-100) and offset for large result sets
@@ -36945,8 +37086,11 @@ async function handleGetNodeInfo(args) {
36945
37086
  return toMCPResponse(response);
36946
37087
  } catch (error) {
36947
37088
  const originalError = error instanceof Error ? error : new Error(String(error));
36948
- const errorResponse = createInternalError(correlationId, originalError);
36949
- return toMCPResponse(errorResponse);
37089
+ if (isDbConfigError(originalError))
37090
+ return makeDbNotConfiguredResponse();
37091
+ if (isDbConnectionError(originalError))
37092
+ return makeDbConnectionErrorResponse();
37093
+ return toMCPResponse(createInternalError(correlationId, originalError));
36950
37094
  }
36951
37095
  }
36952
37096
  var getNodeInfoToolDefinition = {
@@ -37034,8 +37178,11 @@ async function handleFindSimilarPattern(args) {
37034
37178
  return toMCPResponse(response);
37035
37179
  } catch (error) {
37036
37180
  const originalError = error instanceof Error ? error : new Error(String(error));
37037
- const errorResponse = createInternalError(correlationId, originalError);
37038
- return toMCPResponse(errorResponse);
37181
+ if (isDbConfigError(originalError))
37182
+ return makeDbNotConfiguredResponse();
37183
+ if (isDbConnectionError(originalError))
37184
+ return makeDbConnectionErrorResponse();
37185
+ return toMCPResponse(createInternalError(correlationId, originalError));
37039
37186
  }
37040
37187
  }
37041
37188
  var findSimilarPatternToolDefinition = {
@@ -37232,8 +37379,8 @@ schemas, build_workflow handles validation, autofix, and deployment automaticall
37232
37379
 
37233
37380
  Runs L1-L4 validation before creating:
37234
37381
  - L1: JSON structure, required fields
37235
- - L2: Node types exist in catalog (1,982 nodes)
37236
- - L3: Credential types are valid (654 credentials)
37382
+ - L2: Node types exist in catalog (1,545 nodes)
37383
+ - L3: Credential types are valid (679 credentials)
37237
37384
  - L4: Connection patterns exist
37238
37385
 
37239
37386
  Refuses creation if any L1-L4 errors are found.
@@ -38604,7 +38751,7 @@ async function validateWorkflowObject(workflow, timeoutMs, label) {
38604
38751
  }
38605
38752
  async function runAutoFix(workflow, validationResult, timeoutMs, toolName) {
38606
38753
  const problems = validationResult.issues.filter((i) => i.severity === "error").map(issueToValidationProblem2);
38607
- const fixResult = await withTimeout(fixerRegistry.applyFixes(workflow, problems), timeoutMs, `${toolName} autofix`);
38754
+ const fixResult = await withTimeout(getFixerRegistry().applyFixes(workflow, problems), timeoutMs, `${toolName} autofix`);
38608
38755
  return { fixedWorkflow: fixResult.workflow, fixResult };
38609
38756
  }
38610
38757
  async function applyAutoFixIfNeeded(workflow, validationResult, hasErrors, shouldFix, timeoutMs, correlationId, toolName) {
@@ -38825,6 +38972,16 @@ async function warmCredentialCache() {
38825
38972
  import_logging42.logger.warn("credential-cache: warm-up failed (non-fatal)", { error: String(error) });
38826
38973
  }
38827
38974
  }
38975
+ function getCredentialCacheStatus() {
38976
+ if (!cacheState) {
38977
+ return { loaded: false, count: 0, expires_at: null };
38978
+ }
38979
+ return {
38980
+ loaded: true,
38981
+ count: cacheState.credentials.length,
38982
+ expires_at: new Date(cacheState.expires_at).toISOString()
38983
+ };
38984
+ }
38828
38985
  function clearCredentialCache() {
38829
38986
  cacheState = null;
38830
38987
  }
@@ -39241,7 +39398,7 @@ function issueToValidationProblem3(issue) {
39241
39398
  }
39242
39399
  async function runFixStep(workflow, validation, timeoutMs) {
39243
39400
  const problems = validation.issues.filter((i) => i.severity === "error").map(issueToValidationProblem3);
39244
- const fixResult = await withTimeout(fixerRegistry.applyFixes(workflow, problems), timeoutMs, "server_autofix:fix");
39401
+ const fixResult = await withTimeout(getFixerRegistry().applyFixes(workflow, problems), timeoutMs, "server_autofix:fix");
39245
39402
  return {
39246
39403
  fixedWorkflow: fixResult.workflow,
39247
39404
  fixes: extractAppliedFixes(fixResult)
@@ -41271,6 +41428,10 @@ and what service it connects to \u2014 don't attempt to build with a broken cred
41271
41428
  Part of the generation lifecycle: plan_workflow \u2192 test_credential(s) \u2192 build_workflow.
41272
41429
  NOT needed for editing or updating existing workflows (use update_workflow or partial_update_workflow).
41273
41430
 
41431
+ Note: plan_workflow works without n8n (catalog-only mode). To actually deploy
41432
+ workflows with build_workflow, N8N_API_KEY and N8N_API_URL must be configured.
41433
+ Without n8n, use plan_workflow for research and architecture planning only.
41434
+
41274
41435
  Response modes:
41275
41436
  - "full": All research data within token_budget (default 8,000)
41276
41437
  - "summary" (default): Key fields within token_budget (default 4,000)
@@ -43077,7 +43238,12 @@ async function handleGetCredentialSchema(args) {
43077
43238
  return buildSchemaResponse(credential_type, rows, nodes, correlationId, startTime);
43078
43239
  } catch (error) {
43079
43240
  import_logging57.logger.error("get_credential_schema: unexpected error", { correlationId, error });
43080
- return toMCPResponse(createInternalError(correlationId, error instanceof Error ? error : new Error(String(error))));
43241
+ const originalError = error instanceof Error ? error : new Error(String(error));
43242
+ if (isDbConfigError(originalError))
43243
+ return makeDbNotConfiguredResponse();
43244
+ if (isDbConnectionError(originalError))
43245
+ return makeDbConnectionErrorResponse();
43246
+ return toMCPResponse(createInternalError(correlationId, originalError));
43081
43247
  }
43082
43248
  }
43083
43249
  async function handleUnknownType(credentialType, correlationId) {
@@ -44091,6 +44257,129 @@ When values are collected, marks matching factory.gaps entries as resolved for a
44091
44257
  }
44092
44258
  };
44093
44259
 
44260
+ // dist/mcp/tools/handlers/setup-check.js
44261
+ var SETUP_GUIDE_URL2 = "https://github.com/tsvika58/p58-n8n/blob/main/docs/AGENT_INSTALL.md";
44262
+ var N8N_PROBE_TIMEOUT_MS = 2e3;
44263
+ var N8N_PROBE_PORTS = [5678, 5679];
44264
+ async function probeN8nUrl(url2) {
44265
+ const controller = new AbortController();
44266
+ const timer = setTimeout(() => controller.abort(), N8N_PROBE_TIMEOUT_MS);
44267
+ try {
44268
+ const response = await fetch(url2, { signal: controller.signal });
44269
+ const needs_api_key = response.status === 401 || response.status === 403;
44270
+ return { url: url2, status: response.status, needs_api_key, reachable: true };
44271
+ } catch (error) {
44272
+ const message = error instanceof Error ? error.message : String(error);
44273
+ return {
44274
+ url: url2,
44275
+ status: null,
44276
+ needs_api_key: false,
44277
+ reachable: false,
44278
+ error: message.includes("abort") ? "timeout" : message
44279
+ };
44280
+ } finally {
44281
+ clearTimeout(timer);
44282
+ }
44283
+ }
44284
+ async function discoverN8nInstances() {
44285
+ const probeUrls = N8N_PROBE_PORTS.map((port) => `http://localhost:${port}/api/v1/workflows`);
44286
+ return Promise.all(probeUrls.map(probeN8nUrl));
44287
+ }
44288
+ function buildToolCounts() {
44289
+ const total = getRegisteredTools().length;
44290
+ const tier1 = OFFLINE_TOOLS.size;
44291
+ return { tier1, tier2_7: total - tier1 };
44292
+ }
44293
+ function collectIssues(apiKeySet, n8nConnected, probes) {
44294
+ const issues = [];
44295
+ if (!apiKeySet) {
44296
+ issues.push("N8N_API_KEY not set \u2014 Tier 2-7 deploy tools unavailable");
44297
+ }
44298
+ const apiUrlSet = Boolean(process.env.N8N_API_URL ?? process.env.N8N_API_BASE_URL);
44299
+ if (!apiUrlSet && probes) {
44300
+ const reachable = probes.filter((p) => p.reachable);
44301
+ if (reachable.length > 0) {
44302
+ const probeUrl = reachable[0].url.replace("/api/v1/workflows", "");
44303
+ issues.push(`N8N_API_URL not set \u2014 n8n detected at ${probeUrl}. Set N8N_API_URL=${probeUrl}/api/v1 in your MCP config.`);
44304
+ } else {
44305
+ issues.push("N8N_API_URL not set \u2014 no n8n instance detected on localhost:5678 or localhost:5679");
44306
+ }
44307
+ }
44308
+ if (apiKeySet && !n8nConnected) {
44309
+ issues.push("N8N_API_KEY is set but n8n is unreachable \u2014 check N8N_API_URL and ensure n8n is running");
44310
+ }
44311
+ return issues;
44312
+ }
44313
+ async function buildReport() {
44314
+ const apiKeySet = Boolean(process.env.N8N_API_KEY);
44315
+ const n8nUrl = process.env.N8N_API_URL ?? process.env.N8N_API_BASE_URL ?? null;
44316
+ const cacheStatus = getCredentialCacheStatus();
44317
+ const n8nConnected = cacheStatus.loaded;
44318
+ const credentialCount = cacheStatus.loaded ? cacheStatus.count : null;
44319
+ let probes;
44320
+ if (!n8nUrl) {
44321
+ probes = await discoverN8nInstances();
44322
+ }
44323
+ const issues = collectIssues(apiKeySet, n8nConnected, probes);
44324
+ const toolCounts = buildToolCounts();
44325
+ const report = {
44326
+ server_version: config.SERVER_VERSION,
44327
+ n8n_configured: apiKeySet,
44328
+ n8n_url: n8nUrl,
44329
+ n8n_connected: n8nConnected,
44330
+ n8n_api_key_set: apiKeySet,
44331
+ credential_count: credentialCount,
44332
+ catalog_ready: true,
44333
+ tools_available: toolCounts,
44334
+ issues,
44335
+ setup_guide: SETUP_GUIDE_URL2
44336
+ };
44337
+ if (probes) {
44338
+ report.n8n_probes = probes.map((p) => ({
44339
+ ...p,
44340
+ url: p.url.replace("/api/v1/workflows", "/api/v1")
44341
+ }));
44342
+ }
44343
+ return report;
44344
+ }
44345
+ async function handleSetupCheck(_args) {
44346
+ try {
44347
+ const report = await buildReport();
44348
+ return {
44349
+ content: [{ type: "text", text: JSON.stringify(report, null, 2) }]
44350
+ };
44351
+ } catch (error) {
44352
+ const message = error instanceof Error ? error.message : String(error);
44353
+ return {
44354
+ content: [{ type: "text", text: JSON.stringify({ error: `setup_check failed: ${message}` }) }],
44355
+ isError: true
44356
+ };
44357
+ }
44358
+ }
44359
+ var setupCheckToolDefinition = {
44360
+ name: "setup_check",
44361
+ description: `Run this first to check what's configured and what's missing.
44362
+
44363
+ Returns a diagnostic report including:
44364
+ - Server version
44365
+ - n8n connection status (configured/connected/unreachable)
44366
+ - n8n URL (from env var or auto-detected)
44367
+ - Credential count (if n8n is connected)
44368
+ - Tool availability by tier
44369
+ - List of issues with actionable guidance
44370
+ - Link to the setup guide
44371
+
44372
+ When N8N_API_URL is not set, automatically probes localhost:5678 and localhost:5679
44373
+ to detect a local n8n installation.
44374
+
44375
+ Use this after installation to verify everything is working, or to diagnose
44376
+ connection problems.`,
44377
+ inputSchema: {
44378
+ type: "object",
44379
+ properties: {}
44380
+ }
44381
+ };
44382
+
44094
44383
  // dist/mcp/tools/index.js
44095
44384
  var toolRegistry = /* @__PURE__ */ new Map();
44096
44385
  var TOOL_ENTRIES = [
@@ -44127,7 +44416,8 @@ var TOOL_ENTRIES = [
44127
44416
  { name: "test_credential", definition: testCredentialToolDefinition, handler: handleTestCredential },
44128
44417
  { name: "update_credential", definition: updateCredentialToolDefinition, handler: handleUpdateCredential },
44129
44418
  { name: "delete_credential", definition: deleteCredentialToolDefinition, handler: handleDeleteCredential },
44130
- { name: "collect_config", definition: collectConfigToolDefinition, handler: handleCollectConfig }
44419
+ { name: "collect_config", definition: collectConfigToolDefinition, handler: handleCollectConfig },
44420
+ { name: "setup_check", definition: setupCheckToolDefinition, handler: handleSetupCheck }
44131
44421
  ];
44132
44422
  function registerTool(tool) {
44133
44423
  if (!hasSchema(tool.name)) {
@@ -44155,13 +44445,21 @@ async function dispatchToolCall(name, args) {
44155
44445
  const tool = toolRegistry.get(name);
44156
44446
  if (!tool)
44157
44447
  return buildUnknownToolResponse(name);
44158
- if (tool.inputSchema && hasSchema(name)) {
44159
- const validation = validateToolInput(name, args);
44160
- if (!validation.success)
44161
- return createValidationErrorResponse(validation.error);
44162
- return tool.handler(validation.data);
44448
+ if (requiresN8nApiKey(name) && !process.env.N8N_API_KEY) {
44449
+ return makeN8nNotConfiguredError();
44450
+ }
44451
+ incrementInflight();
44452
+ try {
44453
+ if (tool.inputSchema && hasSchema(name)) {
44454
+ const validation = validateToolInput(name, args);
44455
+ if (!validation.success)
44456
+ return createValidationErrorResponse(validation.error);
44457
+ return await tool.handler(validation.data);
44458
+ }
44459
+ return await tool.handler(args);
44460
+ } finally {
44461
+ decrementInflight();
44163
44462
  }
44164
- return tool.handler(args);
44165
44463
  }
44166
44464
  async function handleToolCall(name, args, sessionId = "default") {
44167
44465
  const startTime = Date.now();
@@ -44179,7 +44477,9 @@ function registerAllTools() {
44179
44477
  registerTool({ ...entry, inputSchema: toolSchemas[entry.name] });
44180
44478
  }
44181
44479
  }
44182
- registerAllTools();
44480
+
44481
+ // dist/mcp/server.js
44482
+ init_validatorPostgresClient();
44183
44483
 
44184
44484
  // dist/mcp/middleware/credential-redaction.js
44185
44485
  var MAX_DEPTH = 20;
@@ -44352,6 +44652,7 @@ var defaultDeps = {
44352
44652
  };
44353
44653
  async function runCleanup(serverName, deps) {
44354
44654
  try {
44655
+ await waitForInflightRequests(5e3);
44355
44656
  await deps.shutdownPool();
44356
44657
  deps.clearCache();
44357
44658
  deps.clearConfigCache?.();
@@ -44383,6 +44684,46 @@ function registerShutdownHandlers(serverName, deps) {
44383
44684
  }
44384
44685
 
44385
44686
  // dist/mcp/server.js
44687
+ var SETUP_GUIDE_URL3 = "https://github.com/tsvika58/p58-n8n/blob/main/docs/AGENT_INSTALL.md";
44688
+ var _serverInitialized = false;
44689
+ function isServerInitialized() {
44690
+ return _serverInitialized;
44691
+ }
44692
+ function buildInitializingResponse() {
44693
+ return {
44694
+ content: [{
44695
+ type: "text",
44696
+ text: JSON.stringify({
44697
+ error: "SERVER_INITIALIZING",
44698
+ message: "Server is still loading. Please retry in a moment.",
44699
+ retryAfterMs: 2e3
44700
+ })
44701
+ }],
44702
+ isError: true
44703
+ };
44704
+ }
44705
+ function logStartupSummary(n8nConnected) {
44706
+ const apiKey = process.env.N8N_API_KEY;
44707
+ const n8nUrl = process.env.N8N_API_URL ?? process.env.N8N_API_BASE_URL ?? "http://localhost:5678/api/v1";
44708
+ const totalTools = getRegisteredTools().length;
44709
+ const tier1Count = OFFLINE_TOOLS.size;
44710
+ const tier27Count = totalTools - tier1Count;
44711
+ let n8nStatus;
44712
+ if (!apiKey) {
44713
+ n8nStatus = "not configured (set N8N_API_URL and N8N_API_KEY for deploy tools)";
44714
+ } else if (n8nConnected) {
44715
+ n8nStatus = `connected (${n8nUrl})`;
44716
+ } else {
44717
+ n8nStatus = `configured but unreachable (${n8nUrl})`;
44718
+ }
44719
+ const tier27Status = apiKey && n8nConnected ? `${tier27Count} tools ready` : `${tier27Count} tools unavailable (no N8N_API_KEY)`;
44720
+ console.error(`n8n: ${n8nStatus}`);
44721
+ console.error(`catalog: ready`);
44722
+ console.error(`Tier 1: ${tier1Count} tools ready | Tier 2-7: ${tier27Status}`);
44723
+ if (!apiKey) {
44724
+ console.error(`Setup guide: ${SETUP_GUIDE_URL3}`);
44725
+ }
44726
+ }
44386
44727
  var server = new import_server.Server({
44387
44728
  name: config.SERVER_NAME,
44388
44729
  version: config.SERVER_VERSION
@@ -44405,6 +44746,9 @@ function toCallToolResult(response) {
44405
44746
  server.setRequestHandler(import_types22.CallToolRequestSchema, async (request) => {
44406
44747
  const { name, arguments: args } = request.params;
44407
44748
  try {
44749
+ if (!_serverInitialized) {
44750
+ return toCallToolResult(buildInitializingResponse());
44751
+ }
44408
44752
  const response = await handleToolCall(name, args ?? {});
44409
44753
  return toCallToolResult(redactMCPResponse(response));
44410
44754
  } catch (error) {
@@ -44414,16 +44758,35 @@ server.setRequestHandler(import_types22.CallToolRequestSchema, async (request) =
44414
44758
  });
44415
44759
  async function main() {
44416
44760
  const transport = new import_stdio.StdioServerTransport();
44761
+ const startMs = Date.now();
44417
44762
  await server.connect(transport);
44763
+ console.error(`[INIT] MCP handshake complete in ${Date.now() - startMs}ms`);
44764
+ registerAllTools();
44765
+ _serverInitialized = true;
44418
44766
  const toolCount = getRegisteredTools().length;
44419
- console.error(`${config.SERVER_NAME} v${config.SERVER_VERSION} running on stdio (${toolCount} tools registered)`);
44767
+ console.error(`[INIT] ${toolCount} tools registered in ${Date.now() - startMs}ms`);
44768
+ logStartupSummary(Boolean(process.env.N8N_API_KEY));
44420
44769
  registerShutdownHandlers(config.SERVER_NAME);
44421
- warmCredentialCache().catch((e) => console.error("Credential cache warm-up failed:", e));
44770
+ void warmCredentialCache().catch(() => {
44771
+ });
44772
+ if (process.env.P58_DATABASE_URL || process.env.MCP_DATABASE_URL) {
44773
+ void warmValidatorPool().then(() => {
44774
+ console.error("catalog: connected \u2713");
44775
+ }).catch((err) => {
44776
+ console.error(`catalog: WARNING \u2014 connection failed: ${err.message}`);
44777
+ console.error("catalog: tools will retry on first use, but check P58_DATABASE_URL if errors persist");
44778
+ });
44779
+ }
44422
44780
  }
44423
44781
  main().catch((error) => {
44424
44782
  console.error("Server failed to start:", error);
44425
44783
  process.exit(1);
44426
44784
  });
44785
+ // Annotate the CommonJS export names for ESM import in node:
44786
+ 0 && (module.exports = {
44787
+ isServerInitialized,
44788
+ logStartupSummary
44789
+ });
44427
44790
  /*! Bundled license information:
44428
44791
 
44429
44792
  mime-db/index.js:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@path58/p58-n8n",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "The smartest and fastest n8n MCP server — validate, fix, and discover workflows inside your LLM",
5
5
  "keywords": [
6
6
  "mcp",
@@ -13,9 +13,10 @@
13
13
  ],
14
14
  "author": "Path58",
15
15
  "license": "MIT",
16
+ "homepage": "https://github.com/tsvika58/p58-n8n#readme",
16
17
  "repository": {
17
18
  "type": "git",
18
- "url": "git+https://github.com/tsvika58/n8n-workflow-validator.git"
19
+ "url": "git+https://github.com/tsvika58/p58-n8n.git"
19
20
  },
20
21
  "bin": {
21
22
  "p58-n8n": "dist/mcp/server.bundle.cjs"