Skip to main content
Glama

connectwise-platform-mcp

MCP server for the ConnectWise Platform (formerly known as Asio).

An MCP server that lets Claude (Claude Desktop, Claude Code or another MCP client) work with the ConnectWise Platform partner API, using your own API credentials. You build it from source and run it yourself.

This is not an official ConnectWise product. It is an independent, open-source project. It is not affiliated with, endorsed by or supported by ConnectWise. "ConnectWise" and "Asio" are used only to say which API this talks to.

There is no shared hosted service: each MSP runs its own copy, with its own credentials. Most of this README covers running it on your own machine, where it reads your credentials from a local .env file. You can also host your own copy behind Microsoft Entra sign-in (see The HTTP server). Either way it talks to the ConnectWise API directly and never sends your credentials or data anywhere else.

Contents

Related MCP server: dot API shim

Before you start

You need:

  • Node.js 22.12 or later. Check with node --version.

  • git.

  • A ConnectWise developer portal account (developer.connectwise.com), to download the ConnectWise Platform API spec. The spec is not included in this repository (see below).

  • Rights to create API access in ConnectWise Platform: Primary Admin or Primary Super Admin, or an application role with both "API Access – Update" and "API Access – View".

  • Claude Desktop or Claude Code.

The shell commands below are for macOS and Linux. On Windows, use PowerShell equivalents (for example Copy-Item for cp, New-Item -ItemType Directory for mkdir -p); the npm commands are the same.

Install from source

1. Get the code

git clone https://github.com/steelbrooktech/connectwise-platform-mcp.git
cd connectwise-platform-mcp
npm ci

On npm 12 or later, npm ci may warn that install scripts for esbuild and fsevents were blocked. That is expected and safe to ignore: both are development tools, and everything in this README works without those scripts.

2. Add the ConnectWise API spec

The server's tools are generated from ConnectWise's OpenAPI spec. That file is ConnectWise's, so it is not in this repository: you download it yourself.

  1. Sign in to the ConnectWise developer portal at developer.connectwise.com.

  2. Go to ConnectWise Platform > Platform Partners > REST API > Current API.

  3. Download the OpenAPI spec file, currentPartnerAPI.yaml.

  4. Save it in this folder as docs/connectwise-platform/currentPartnerAPI.yaml:

mkdir -p docs/connectwise-platform

Then move the downloaded file there. For example, on macOS:

mv ~/Downloads/currentPartnerAPI.yaml docs/connectwise-platform/

docs/ is listed in .gitignore, so the spec is never committed.

This project was built against spec version 3.2.0. If ConnectWise has published a newer version, the next step may stop and list the operations that differ from config/scope-map.json. Nothing is guessed: open an issue, or update the scope map yourself.

3. Generate the tools and build

npm run generate

This reads the spec plus config/scope-map.json, config/tool-groups.json and config/api-quirks.json, and writes the tool catalogue to src/core/generated/. It should end with Warnings: 0 and Wrote .../src/core/generated/operations.json.

npm run build

Optionally, run the tests (no network, no credentials needed):

npm test

Create an API key in ConnectWise Platform

Start with read scopes only. You can add write scopes later if you decide to use full mode.

  1. In ConnectWise Platform, go to Integrations > API Access.

  2. Click + Generate API Access.

  3. Enter an API Key Name (for example "Claude MCP, read only") and a Description.

  4. From Scopes, select the read scopes for the areas you want Claude to see. The scope checklist lists them per tool group. For a first try, Companies, Sites, Devices and Tickets Read are enough.

  5. Tick Consent, then click Generate API Access.

  6. Copy the Client ID and Client Secret straight into your .env file (next section) or a password manager. The Client Secret is shown only once. If you lose it, use Regenerate, which replaces both values.

Note: with read scopes only, ConnectWise itself refuses any write, whatever this server's mode. The scopes on the credential are the real limit; this server's modes are an extra layer on top.

Configure

cp .env.example .env

Edit .env:

Setting

Required

Values

Default

CWP_CLIENT_ID

yes

from API Access

CWP_CLIENT_SECRET

yes

from API Access

CWP_REGION

no

us, eu, au

us

CWP_MODE

no

read_only, full

read_only

CWP_ENABLE_SENSITIVE

no

see Sensitive operations

empty

CWP_TOOL_GROUPS

no

comma-separated, for example devices,tickets

all groups

.env is listed in .gitignore. Never commit it or paste its contents anywhere.

Check that the credential works (one token request and one rate-limit request, both read-only; prints statuses and scope names, never the token):

npm run live-check

Connect it to Claude

Find the full path of this folder (you need it below):

pwd

Claude Code

Option A: only inside this folder. The repository has a .mcp.json that starts the server from dist/. Run claude in this folder. The first time, Claude Code asks whether you trust the folder (accept), then asks you to approve the project's MCP server: approve connectwise-platform. Until you do, claude mcp list shows it as "Pending approval".

Option B: in every project. Register it for your user, with absolute paths. Replace /path/to/connectwise-platform-mcp with the output of pwd:

claude mcp add --scope user --transport stdio connectwise-platform -- node --env-file=/path/to/connectwise-platform-mcp/.env /path/to/connectwise-platform-mcp/dist/index.js

Options come before the name connectwise-platform; everything after -- is the command that starts the server. This reads the credentials from your .env file, so the secret is not copied into Claude Code's own settings. (You could pass them with -e KEY=value instead, but then they are stored in ~/.claude.json.)

Check it:

claude mcp list

It should show connectwise-platform as connected. Inside a Claude Code session, /mcp shows the same.

Claude Desktop

  1. Find the full path of node. Claude Desktop does not always see the same PATH as your terminal, so use the full path:

    which node
  2. Open the config file: in Claude Desktop, Settings > Developer > Edit Config. It is at:

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

    • Windows: %APPDATA%\Claude\claude_desktop_config.json

  3. Add this server under mcpServers (keep any servers already there). Use absolute paths only:

    {
      "mcpServers": {
        "connectwise-platform": {
          "command": "/full/path/to/node",
          "args": [
            "--env-file=/path/to/connectwise-platform-mcp/.env",
            "/path/to/connectwise-platform-mcp/dist/index.js"
          ]
        }
      }
    }

    On Windows, write paths with forward slashes or doubled backslashes, for example "C:/Users/you/connectwise-platform-mcp/dist/index.js".

  4. Quit Claude Desktop completely and start it again.

Modes: what Claude can see

Set with CWP_MODE in .env. What each mode exposes comes from config/scope-map.json, not from a hand-kept list. After changing .env, restart Claude Desktop, or in Claude Code run /mcp and reconnect connectwise-platform, so the server reads it again.

Mode

Tools

Operations

read_only (default)

11 read tools (cwp_devices, cwp_tickets, ...) plus cwp_describe_operation

105 reads. No writes. The two sensitive reads stay hidden unless opted in.

full

the same 11 read tools, 7 write tools (cwp_devices_write, cwp_tickets_write, ...), cwp_confirm_write plus cwp_describe_operation

105 reads and 37 writes. Ten writes need a confirm step.

  • Each tool covers one area. Claude picks an operation and passes its parameters in params; cwp_describe_operation shows any operation's parameters, paging and required scope.

  • CWP_TOOL_GROUPS narrows either mode to some areas, for example devices,tickets. Groups: automation, backup_dashboard, cloud_backup, companies, custom_fields, devices, patching, platform, policies, security_cases, tickets.

  • Large lists are paged. When more results exist, a result includes next_page; Claude passes those values back to get the next page.

The confirm step for high-impact operations

In full mode, ten operations never run through their own tool. Their _write tool only returns a preview, and a separate tool, cwp_confirm_write, carries them out:

Operation

Tool

What it does

schedule_task

cwp_automation_write

Runs a script or task on client endpoints. Highest-impact operation.

delete_device_endpoints_uninstall

cwp_devices_write

Uninstalls the agent from endpoints.

post_api_platform_v2_device_endpoints_move

cwp_devices_write

Moves devices to another company and site, which can change which policies and deployments apply to them. The move can take 15 to 30 minutes to show.

cancel_backup_subscription

cwp_cloud_backup_write

Cancels a cloud backup subscription.

suspend_backup_subscription

cwp_cloud_backup_write

Suspends a cloud backup subscription.

revoke_customer_access

cwp_cloud_backup_write

Revokes a customer user's access to a backup subscription.

delete_api_platform_v1_service_ticketing_tags_id

cwp_tickets_write

Deletes a ticket tag.

put_api_platform_v1_company_companies_company_id_custom_fields

cwp_custom_fields_write

Sets custom field values on a company. May trigger automatic deployment to every device in the company if the field drives a monitor.

put_api_platform_v1_company_sites_site_id_custom_fields

cwp_custom_fields_write

Sets custom field values on a site. May trigger automatic deployment to every device at the site if the field drives a monitor.

put_api_platform_v2_device_endpoints_endpoint_id_custom_fields

cwp_custom_fields_write

Sets custom field values on a device. May trigger automatic deployment to this device if the field drives a monitor.

Why custom field values: a common setup is a company field such as "BlackPoint Enabled" that a monitor watches, so ticking it installs software on every device in that company. The API cannot show which fields drive monitors, so every custom field value write is treated as possibly high-impact.

How it works:

  1. Calling the operation through its _write tool returns a preview and changes nothing. It never does more, even if Claude passes confirm. The preview makes no network call at all (not even for a token). It has a plain-English headline (for example "This will schedule a script on 2 endpoints"), target counts, the exact request, the region, the console scope needed, and the read tools Claude should use to look up names for the IDs. For custom field writes, the headline lists each field (by ID) with its new value, and any value that looks like a token, key or opaque ID (16 or more characters, no spaces, letters and digits) is masked to its first 4 characters, in the request shown as well. The real value is still sent on confirm.

  2. The preview tells Claude to stop there. It says that an instruction given before the preview existed is not approval, even one asking for this exact change. Claude should look up the device, company and script names (and, for custom field writes, the field names and their current values), show them to you with the preview, end its turn, and wait for you.

  3. Only after you reply with an explicit yes, Claude calls cwp_confirm_write with the same tool, operation and parameters, within 10 minutes of the preview.

  4. Each preview can be confirmed once. Any change to the parameters gets a fresh preview instead. Previews are kept in memory only, so restarting the server means a new preview.

Step 2 is an instruction to Claude, and Claude can still get it wrong. What actually stops it depends on your app; see Making sure a person approves.

The other 27 writes run when called (in full mode only). No write is ever retried after a timeout or a server error: the message says the outcome is unknown and to check in ConnectWise before trying again.

Making sure a person approves

The confirm step stops a change from running on the first call. On its own, it cannot tell whether you or Claude approved the preview. Two settings close that gap in Claude Code.

The confirm tool always asks, in Claude Code. cwp_confirm_write is marked with _meta["anthropic/requiresUserInteraction"]: true. Claude Code then asks you before every call to it, in every permission mode, including auto mode and bypass mode, and an allow rule cannot skip it. The prompt shows the exact tool, operation and parameters about to run. See Require approval for a specific tool. This is a Claude Code feature, not part of the MCP standard. Claude Desktop and other MCP clients ignore it, so there the preview instructions and the app's own approval settings are all you have.

Recommended: an ask rule for every write tool. Add this to ~/.claude/settings.json (all your projects) or .claude/settings.local.json (this project, just you):

{
  "permissions": {
    "ask": ["mcp__connectwise-platform__cwp_*_write"]
  }
}

Claude Code then asks before any write, including the 27 that have no preview, such as renaming a device. Ask rules apply in auto mode as well, and an ask rule wins over an allow rule that matches the same tool. If your server has a different name in your MCP config, use that name in place of connectwise-platform. To check the rule works, ask Claude for a harmless write and look for the prompt.

What each layer can and cannot do:

Layer

Where it works

What it guarantees

Credential scopes

Everywhere

The API refuses anything the credential has no scope for.

Preview, then cwp_confirm_write

Every client

A confirm operation never runs on its first call, and only runs with the exact preview. Approval is an instruction to Claude, not enforced.

requiresUserInteraction on cwp_confirm_write

Claude Code only

You are asked before every confirm operation runs, whatever the mode. In dontAsk mode the call is denied.

Ask rule for cwp_*_write

Claude Code, on the machine where you set it

You are asked before every write, previews included.

Per-tool permissions in Claude

Safety comes in layers, strongest first:

  1. The scopes on your ConnectWise credential. This is the real enforcement: without a scope, the API refuses the call.

  2. This server's mode and confirm step. read_only hides every write tool. In full mode, high-impact operations return a preview first.

  3. Your Claude app's own permission prompts and rules, described below.

Every tool tells Claude what kind it is. Read tools are marked readOnlyHint: true; _write tools are marked destructiveHint: true and readOnlyHint: false. Under the MCP specification these are hints, and clients must treat them as untrusted, so do not rely on them as a control. Neither Claude app documents using them to approve or block calls.

Claude Code. In the default mode, Claude Code asks before the first use of each tool. You can set rules in .claude/settings.json (shared with the project), .claude/settings.local.json (just you, this project) or ~/.claude/settings.json (just you, everywhere), and see them all with /permissions. MCP tools are named mcp__<server>__<tool>, so with the server named connectwise-platform:

{
  "permissions": {
    "allow": ["mcp__connectwise-platform__cwp_devices", "mcp__connectwise-platform__cwp_describe_operation"],
    "ask": ["mcp__connectwise-platform__cwp_*_write"]
  }
}

mcp__connectwise-platform (or mcp__connectwise-platform__*) covers every tool on the server. Rules match whole tools, not the operation inside one, so the confirm step is what separates high-impact operations from routine ones within a write tool. See Claude Code permissions and Claude Code MCP.

Claude Desktop. For connectors, Claude Desktop lets you set each tool to Always allow, Needs approval or Blocked (see Use connectors). Anthropic's pages on local servers added through claude_desktop_config.json or as desktop extensions do not currently describe per-tool settings for them, so check what your version of the app shows. Keep write tools on approval rather than Always allow.

Sensitive operations (opt-in)

Two reads are hidden in both modes unless you name them in CWP_ENABLE_SENSITIVE (comma-separated):

CWP_ENABLE_SENSITIVE=get_endpoint_session_details,post_device_installation_token
  • get_endpoint_session_details returns remote-access session details for endpoints. Needs "Platform - Remote Access - Read".

  • post_device_installation_token generates or returns an agent install token, which can enroll new devices into your tenant. ConnectWise lets any credential with "Platform - Devices - Read" call it, so an ordinary read-only credential could create install tokens. That is why this server hides it by default, even in read_only mode.

Opt in only to the one you need, and only if you understand what it exposes.

Scope checklist

Scopes as named under Integrations > API Access, per tool group. "Used by" says whether read or write operations need the scope (write tools exist only in full mode).

Status:

  • verified: tested on a live tenant. The operation returned 200 with the scope on the credential and 403 after the scope was removed. Ten scopes were removed together in one run.

  • documented: ConnectWise's documentation names this scope for the operation. Not tested by removing it.

  • inferred: the documentation names no scope. The scope here is a best guess from the API area and method.

  • unknown: a guess was tested and was wrong. The message on a 403 says what was tried.

A mixed status, such as "verified (5), inferred (2)", means the scope's operations differ. Run cwp_describe_operation for the detail on each one.

automation (cwp_automation)

Console scope

Used by

Operations

Status

Platform - Automation - Create

write

1

inferred

Platform - Automation - Read

read

7

verified (5), inferred (2)

backup_dashboard (cwp_backup_dashboard)

Console scope

Used by

Operations

Status

Backup Dashboard - Read alarms

read

1

documented

Backup Dashboard - Read backup jobs

read

1

documented

Backup Dashboard - Read DR readiness

read

1

documented

cloud_backup (cwp_cloud_backup)

Console scope

Used by

Operations

Status

Platform - Backup - Create

write

6

documented

Platform - Backup - Delete

write

3

documented

Platform - Backup - Read

read

8

documented

companies (cwp_companies)

Console scope

Used by

Operations

Status

Platform - Companies - Read

read

2

verified

Platform - Companies - Write

write

3

inferred

Platform - Contacts - Write

write

1

inferred

Platform - DataMapping - Read

read

1

verified

Platform - Sites - Read

read

4

verified

Platform - Sites - Write

write

3

inferred

custom_fields (cwp_custom_fields)

Console scope

Used by

Operations

Status

Platform - Custom Fields Definitions - Read

read

1

verified

Platform - Custom Fields Definitions - Write

write

2

inferred

Platform - Custom Fields Values - Read

read

3

verified

Platform - Custom Fields Values - Write

write

3

inferred

(not known)

read

1 (get_api_platform_v1_custom_field_definitions_definition_id)

unknown

devices (cwp_devices)

Console scope

Used by

Operations

Status

Platform - DeviceGroups - Read

read

3

documented

Platform - Devices - Delete

write

1

documented

Platform - Devices - Read

read (includes opt-in post_device_installation_token)

20

documented (19), inferred (1)

Platform - Devices - Write

write

2

documented (1), inferred (1)

Platform - Remote Access - Read

read (includes opt-in get_endpoint_session_details)

1

documented

Platform - Suspension - Read

read

2

verified

patching (cwp_patching)

Console scope

Used by

Operations

Status

Platform - OS Patching - Read

read

3

documented

Platform - Os Patching Endpoint Patches (read)

read

1

verified

Platform - Third Party Patching - Read

read

2

documented

Security - Vulnerabilities - Read

read

1

verified

platform (cwp_platform)

Console scope

Used by

Operations

Status

(none needed)

read

1 (get_current_rate_limit)

none needed

policies (cwp_policies)

Console scope

Used by

Operations

Status

Platform - Policy - Read

read

12

documented

security_cases (cwp_security_cases)

Console scope

Used by

Operations

Status

Security - Cases - Read

read

17

documented

Security - Cases - Write

write

2

documented

tickets (cwp_tickets)

Console scope

Used by

Operations

Status

Platform - Tickets - Create

write

3

inferred

Platform - Tickets - Read

read

14

verified

Platform - Tickets - Update

write

7

inferred

This table is generated from config/scope-map.json (npm run scope-checklist -- --write). A test checks that it is up to date.

What the error messages mean

The server turns HTTP errors into plain messages. It never puts the token or secret in a message.

Status

When

What to do

401

The token request was refused, or the API refused the token even after a fresh one.

Check CWP_CLIENT_ID, CWP_CLIENT_SECRET and CWP_REGION, and that the API access is still enabled under Integrations > API Access.

403

The credential lacks the scope for this operation.

The message names the console scope from the scope checklist and says how sure that is (verified, documented, best guess or unknown). Add the scope under Integrations > API Access.

423

ConnectWise locked token requests because new tokens were requested too often.

Wait a few minutes. The server caches its token and keeps using it until shortly before it expires, so this is rare.

429

Rate limit reached. ConnectWise documents 500 requests per 5 minutes per token; in testing the remaining count was reported separately per route.

The server waits and retries (up to 60 seconds, at most twice). If the wait would be longer, it stops and says when to try again. Results warn when a route is down to its last 10%.

503

"Service not implemented": the service is not available to this account or region.

The message says the service may not be enabled for your account or region. Seen for the Cloud Backup operations. Not retried. Other 503s on reads are retried once.

Some operations answer 404 when there is simply nothing to return (for example no open threats, or no metrics stored for an endpoint). For those, the server returns an empty result with a note quoting ConnectWise's message instead of an error. The list, with the evidence for each, is in config/api-quirks.json. A 404 from any other operation is an error.

Known limits

Tested against one live tenant, read-only. Not everything could be exercised:

  • No write operation (37) has been called against a live tenant. They are tested against a mock server only, for method, path and body.

  • The two sensitive reads have not been called live.

  • Never returned 200 live (so their response shapes are untested):

    • Cloud Backup: all 8 reads. get_subscriptions, get_alerts_health and get_data_centers answered 503 "Service not implemented"; the 5 detail reads need a subscription ID from get_subscriptions.

    • Security cases: the 13 per-threat reads (there were no open threats to read) and the 3 summaries plus list_cases (only seen as "no data").

    • The 2 task-instance reads (task_instance_summary, task_instance_execution_results): the task list returns no task IDs.

    • get_api_platform_v1_custom_field_definitions_definition_id: 403 with the scope tried; the right scope is unknown.

    • Seen only as "no data" (404) for the one endpoint tested: CPU, memory and disk usage, the memory and processor time series, endpoint relations, effective policy override, and hypervisor hosts.

  • post_api_platform_v1_mapping_mappings_lookup was only called with an empty request body.

  • Only the us region has been tested.

  • The legacy ConnectWise API is out of scope.

Development

npm test

Runs the unit tests against mocks. Tests that need the ConnectWise spec are skipped if it is not present.

These scripts call your own tenant, read-only, with the credentials in .env. They print statuses, counts and field names, never record contents:

  • npm run live-check: token and rate-limit check.

  • npm run build && npm run live-tools: a few read tools through the server.

  • npm run build && npm run live-smoke: every non-sensitive read once. Writes a report to test/live/reports/ (gitignored).

Other files worth knowing:

  • config/scope-map.json: per-operation scope, read or write, confirm and sensitive flags.

  • config/api-quirks.json: corrections to the spec seen live, each with its evidence.

  • config/tool-groups.json: which API area goes in which tool.

How the code is laid out

  • src/core/: the library. Settings, the operation catalogue, mode filtering, the API client and token, the confirm gate and previews, and store.ts, which holds the token and previews either in memory or in a key-value service (encrypted token, previews as fingerprints only).

  • src/index.ts: the stdio server that Claude Desktop and Claude Code start.

  • src/remote.ts and src/remote/: an MCP server over Streamable HTTP.

The HTTP server (self-hosting)

npm run build && npm run start:remote

It listens on http://127.0.0.1:8787/mcp (change the port with CWP_HTTP_PORT). Without sign-in (CWP_AUTH=none, the default) it listens on this machine only. With CWP_AUTH=entra, every call needs a Microsoft Entra token from an allowed user; see src/remote/entra.ts for its settings and plans/hosting-setup.md for hosting it on Vercel (api/mcp.ts). It reads the same CWP_* settings, plus:

Variable

Meaning

CWP_STORE

memory (default) or redis-rest

CWP_STORE_URL, CWP_STORE_TOKEN

For redis-rest: a Redis REST endpoint (Upstash-style) and its token

CWP_STORE_ENCRYPTION_KEY

For redis-rest: 32 random bytes, base64 (openssl rand -base64 32). Encrypts the cached ConnectWise token

CWP_STORE_NAMESPACE

Optional key prefix (default connectwise-platform)

Licence

MIT. See LICENSE.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables MCP clients like Claude Code or Codex to administer a Bifrost LLM gateway's governance API, including virtual keys, teams, customers, budgets, provider configs, routing rules, model/pricing config, request-log observability, and core gateway config.
      17 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      F
      maintenance
      Enables a private, owner-authenticated MCP client to call approved upstream APIs through a server-owned registry, with server-held credentials, fixed origins, bounded responses, and distinct read/write tools. Writes are opt-in and durably recorded with stable operation identifiers.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables Claude Desktop, Cursor, and other MCP-aware clients to conversationally manage endpoints, query and triage alerts, inspect events, manage policies and intel feeds, mint enrollment tokens, and preview or commit fleet changes.
      26
      263 npm
      Apache 2.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      Turns a company's upstream APIs into multi-tenant MCP endpoints that Claude and other MCP clients can call, with per-organization and per-role tool and field allowlists, API keys or OAuth 2.1 authorization, upstream token minting, pagination, retries, rate limiting, and an audit log for every call.
      49 npm
      MIT