selic

mcp-connectwise-psa

Community selic
Updated

mcp-connectwise-psa

An MCP (Model Context Protocol) server for ConnectWise PSA (Manage), focused on what technicians do all day:

  • Tickets — my tickets, search, full detail with notes, create, update status/priority/owner, add discussion/internal notes
  • Time entries — log time against tickets, review your own time
  • Companies & contacts — fast lookup (read-only)
  • Configurations — devices/assets with serials, IPs, OS, warranty (read-only)
  • Role-based access control — viewer / editor bearer tokens decide which tools a session sees
  • Per-tech API keys (BYOK) — techs supply their own ConnectWise member keys, so notes and time entries are attributed to the actual person in ConnectWise
  • Transports — stdio for local use, streamable HTTP for shared deployments; Docker image included

Quick start (local, stdio)

npm install && npm run build
CW_SITE=na.myconnectwise.net \
CW_COMPANY_ID=yourcompany \
CW_CLIENT_ID=<integration clientId> \
CW_PUBLIC_KEY=xxxx CW_PRIVATE_KEY=yyyy \
CW_MEMBER_IDENTIFIER=JSmith \
node dist/index.js

Claude Desktop / Claude Code config:

{
  "mcpServers": {
    "connectwise": {
      "command": "node",
      "args": ["/path/to/mcp-connectwise-psa/dist/index.js"],
      "env": {
        "CW_SITE": "na.myconnectwise.net",
        "CW_COMPANY_ID": "yourcompany",
        "CW_CLIENT_ID": "<clientId>",
        "CW_PUBLIC_KEY": "xxxx",
        "CW_PRIVATE_KEY": "yyyy",
        "CW_MEMBER_IDENTIFIER": "JSmith"
      }
    }
  }
}

A clientId is required by the ConnectWise API — register a (free) integration at developer.connectwise.com. API member keys are created in ConnectWise under My Account → API Keys (per member) or System → Members → API Members (integration accounts).

HTTP deployment

CW_SITE=… CW_COMPANY_ID=… CW_CLIENT_ID=… \
MCP_TOKENS_VIEWER="alice:$(openssl rand -hex 32)" \
MCP_TOKENS_EDITOR="bot:$(openssl rand -hex 32)" \
node dist/index.js --transport http --port 3000

Or with Docker: docker build -t mcp-connectwise-psa . && docker run -p 3000:3000 -e CW_SITE -e CW_COMPANY_ID -e CW_CLIENT_ID -e MCP_TOKENS_VIEWER -e MCP_TOKENS_EDITOR mcp-connectwise-psa

Route Purpose
POST/GET/DELETE /mcp MCP streamable-http endpoint
GET /health Liveness probe

Sessions are held in memory — run a single instance (or sticky sessions).

Access control

Role tokens

MCP_TOKENS_VIEWER="alice:tokA,bob:tokB"   # read-only tools
MCP_TOKENS_EDITOR="helpdesk-bot:tokC"     # + create/update tickets, notes, time entries
MCP_TOKENS_ADMIN="ops:tokD"               # reserved for future destructive tools

Clients send Authorization: Bearer <token>. Tools outside the role are not even registered for the session, a runtime guard re-checks every call, and session ids never carry privilege (each request re-authenticates; principal mismatch → 403). Labels appear in the audit log and allow per-person revocation. With no tokens configured the server runs in dev mode (full access + loud warning).

Bring your own keys (BYOK) — recommended for techs

Send your own ConnectWise member API keys on the initialize request:

x-cw-public-key:  <public key>
x-cw-private-key: <private key>
x-cw-member-id:   <your member identifier>   (optional — enables "my tickets"/"my time")

The session then acts as you in ConnectWise: your security role limits what succeeds, and every note and time entry is attributed to you. CLIENT_CW_KEYS controls the policy: with-token (default — a bearer token is still required), open, or disabled. Keys are never logged; sessions are bound to a SHA-256 hash of the pair.

Token-only sessions use the server-wide CW_PUBLIC_KEY/CW_PRIVATE_KEY (use an integration API member with a conservative security role — its writes are attributed to that integration member).

Tools

Tool Tier
cw_my_tickets, cw_search_tickets, cw_get_ticket read
cw_list_my_time read
cw_search_companies, cw_get_company, cw_search_contacts read
cw_list_configurations, cw_get_configuration read
cw_create_ticket, cw_update_ticket, cw_add_ticket_note write
cw_create_time_entry write

Viewer = read. Editor/Admin = read + write. No destructive (delete) tools in v1.

Configuration reference

Variable Default Purpose
CW_SITE ConnectWise host (cloud or on-prem; full URLs accepted)
CW_COMPANY_ID Login company id
CW_CLIENT_ID Integration clientId
CW_PUBLIC_KEY / CW_PRIVATE_KEY Server-wide API member keys (optional when BYOK is enabled)
CW_MEMBER_IDENTIFIER Member the server-wide keys belong to
TRANSPORT / PORT stdio / 3000 Transport selection
CLIENT_CW_KEYS with-token BYOK policy: disabled, with-token, open
MCP_TOKENS_VIEWER/EDITOR/ADMIN label:token,label:token per role

Notes & limits

  • Ticket searches default to open tickets; status/board names are exact, text filters are substrings.
  • Timestamps must have whole seconds — the server normalizes (ConnectWise rejects fractional seconds).
  • Time entries require an open time report period in ConnectWise for the entry date; the API's message is passed through when none exists.
  • /system/myAccount is missing on some on-prem versions — provide the member identifier explicitly (CW_MEMBER_IDENTIFIER or x-cw-member-id) for "my tickets"/"my time".
  • Discussion notes are customer-visible; internal notes are not — the tool makes this explicit.

Development

npm install
npm run dev          # stdio via tsx
npm run dev:http     # http via tsx
npm test             # vitest
npm run build        # tsc → dist/

License

MIT

MCP Server · Populars

MCP Server · New