Files
zeus-skills/ops/connectwise/connectwise-n8n-automation/SKILL.md
T

62 lines
5.3 KiB
Markdown

---
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 <base64>` 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.