--- name: connectwise-n8n-automation description: Use when automating ConnectWise PSA tasks via n8n workflows. --- # ConnectWise n8n Automation Use when automating ConnectWise PSA tasks (fetching tickets, updating owners, summarizing notes) using n8n workflows via MCP. ## Workflow 1. **Identify Workflow**: Search for existing workflows using `mcp__n8n__search_workflows`. 2. **Inspect Schema**: Use `mcp__n8n__get_workflow_details` to understand required input parameters (e.g., `username`, `ticketId`). 3. **Execute**: Use `mcp__n8n__execute_workflow`. 4. **Retrieve Results**: - Use `mcp__n8n__get_execution` with `includeData: true`. - If the result is large and truncated to a file (e.g., `/tmp/hermes-results/...`), use `read_file` and `execute_code`. 5. **Verification**: If a workflow is supposed to update data, verify the change by re-fetching the record. ## Pitfalls & Lessons ### 1. Parsing Truncated Tool Outputs When `mcp__n8n__get_execution` returns a result too large for the context, Hermes saves it to a file. These files are **not** raw JSON; they are line-numbered (e.g., `1|{"result": ...}`). - **Wrong**: `json.loads(file_content)` - **Right**: `json_str = line.split('|', 1)[1].strip()` before parsing. ### 2. User Filtering Ambiguity ConnectWise nodes in n8n may use different fields for "username". - If filtering by `SBrown` (identifier) returns 0 results but you know tickets exist, try `Scott Brown` (full name). - The workflow's internal query often uses `owner/name like ...`, which may require the human-readable name. ### 3. API Auth (n8n vs. Direct) Direct API calls via `execute_code` (using `requests`) often fail with `401 Unauthorized` even with correct Public/Private keys because they lack the required `clientId` (UUID). - **Guidance**: Always prefer existing n8n workflows for ConnectWise actions. If no workflow exists, create one using `mcp__n8n__create_workflow_from_code` to leverage n8n's managed credentials. ### 4. Long-Running LLM Workflows Workflows utilizing AI (e.g., Ollama for summarization) take significantly longer than standard API la calls. - **Action**: Poll `mcp__n8n__get_execution` multiple times or implement a wait loop in `execute_code` before attempting to read the final results. ### 5. MCP Server Access: Two Servers, Two Tokens, SSE Result Framing - TWO n8n MCP servers exist: tallerhawk (token in ~/.hermes/.env as N8N_API_KEY) and n8n.vistanetinc.com (token ONLY in config.yaml under mcp_servers). The .env token returns `Unauthorized` against vistanetinc — pull the config.yaml one instead. - Raw HTTP MCP works: POST to /mcp-server/http with Accept: 'application/json, text/event-stream'; responses are SSE frames. The RESULT frame is the first `data:` frame containing a `result` key (it often has NO `id` key — don't wait for id==1). - search_workflow_executions: server retains only ~30 recent executions server-wide; `status` filter param is not accepted; filter by workflowId param works but also just filter client-side by scanning. `nextCursor` pagination exists but the retained window is tiny anyway. - Direct API Auth & Headers: same as below Direct API calls via `execute_code` (using `requests`) fail with `401 Unauthorized` if the `clientId` and `companyId` are missing from the headers, even if Basic Auth is correct. - **Required Headers**: - `clientId`: UUID of the client application. - `companyId`: The company identifier (e.g., `VNI`). - **Auth String Format**: The username must be constructed as `companyid+publickey`. If the public key already starts with a `+`, do not add an additional `+` between the company ID and the key (to avoid the "double-plus bug"). - **Correct Base64 Pattern**: `base64(companyid+publickey:privatekey)`. - **Correction**: Ensure both headers are present alongside Basic Auth. If standard `auth=(user, pass)` parameters fail, manually construct the `Authorization: Basic ` header. ### 7. Trigger-Specific Data Mapping (MCP vs Webhook) When triggering a workflow via the `execute_workflow` MCP tool, input data is injected at the root level, whereas real HTTP requests put data under the `body` object. - **Pitfall**: An n8n workflow starting with a Webhook trigger will see an empty `$json.body` when executed via MCP, causing downstream nodes to fail or receive `undefined`. - **Fix**: Add a **Set (Edit Fields)** node immediately after the trigger to normalize the data using nullish coalescing: - `ticketId` $\rightarrow$ `{{ $json.body?.ticketId ?? $json.ticketId }}` - `memberId` $\rightarrow$ `{{ $json.body?.memberId ?? $json.memberId }}` - **Result**: Downstream nodes can now safely use `{{ $json.ticketId }}` regardless of how the workflow was triggered. ### 8. PSA Release Notes Are Not Programmatically Reachable docs.connectwise.com's PSA release-notes tree is SSO-gated and blocks anonymous datacenter IPs at the CDN edge (every fetch returns a login interstitial; Wayback/archive.today hold zero captures). When asked what a release contains: verify CVE/security-bulletin facts from public bulletins first — those ARE fetchable — then route functional release-note questions to the user (ConnectWise Home release-notes widget on their logged-in console) instead of cycling anonymous recovery ladders. For a full pull, ask the user to save partner-portal credentials to the vault so the docs site can be logged into.