connectwise-platform
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
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.gitcd connectwise-platform-mcpnpm ciOn 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.
Sign in to the ConnectWise developer portal at developer.connectwise.com.
Go to ConnectWise Platform > Platform Partners > REST API > Current API.
Download the OpenAPI spec file,
currentPartnerAPI.yaml.Save it in this folder as
docs/connectwise-platform/currentPartnerAPI.yaml:
mkdir -p docs/connectwise-platformThen 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 generateThis 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 buildOptionally, run the tests (no network, no credentials needed):
npm testCreate an API key in ConnectWise Platform
Start with read scopes only. You can add write scopes later if you decide to use full mode.
In ConnectWise Platform, go to Integrations > API Access.
Click + Generate API Access.
Enter an API Key Name (for example "Claude MCP, read only") and a Description.
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.
Tick Consent, then click Generate API Access.
Copy the Client ID and Client Secret straight into your
.envfile (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 .envEdit .env:
Setting | Required | Values | Default |
| yes | from API Access | |
| yes | from API Access | |
| no |
|
|
| no |
|
|
| no | empty | |
| no | comma-separated, for example | 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-checkConnect it to Claude
Find the full path of this folder (you need it below):
pwdClaude 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.jsOptions 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 listIt should show connectwise-platform as connected. Inside a Claude Code session, /mcp
shows the same.
Claude Desktop
Find the full path of
node. Claude Desktop does not always see the samePATHas your terminal, so use the full path:which nodeOpen the config file: in Claude Desktop, Settings > Developer > Edit Config. It is at:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
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".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 |
| 11 read tools ( | 105 reads. No writes. The two sensitive reads stay hidden unless opted in. |
| the same 11 read tools, 7 write tools ( | 105 reads and 37 writes. Ten writes need a confirm step. |
Each tool covers one area. Claude picks an
operationand passes its parameters inparams;cwp_describe_operationshows any operation's parameters, paging and required scope.CWP_TOOL_GROUPSnarrows either mode to some areas, for exampledevices,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 |
|
| Runs a script or task on client endpoints. Highest-impact operation. |
|
| Uninstalls the agent from endpoints. |
|
| 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. |
|
| Cancels a cloud backup subscription. |
|
| Suspends a cloud backup subscription. |
|
| Revokes a customer user's access to a backup subscription. |
|
| Deletes a ticket tag. |
|
| Sets custom field values on a company. May trigger automatic deployment to every device in the company if the field drives a monitor. |
|
| Sets custom field values on a site. May trigger automatic deployment to every device at the site if the field drives a monitor. |
|
| 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:
Calling the operation through its
_writetool returns a preview and changes nothing. It never does more, even if Claude passesconfirm. 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.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.
Only after you reply with an explicit yes, Claude calls
cwp_confirm_writewith the same tool, operation and parameters, within 10 minutes of the preview.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 | 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. |
| Claude Code only | You are asked before every confirm operation runs, whatever the mode. In |
Ask rule for | 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:
The scopes on your ConnectWise credential. This is the real enforcement: without a scope, the API refuses the call.
This server's mode and confirm step.
read_onlyhides every write tool. Infullmode, high-impact operations return a preview first.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_tokenget_endpoint_session_detailsreturns remote-access session details for endpoints. Needs "Platform - Remote Access - Read".post_device_installation_tokengenerates 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 inread_onlymode.
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 |
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_healthandget_data_centersanswered 503 "Service not implemented"; the 5 detail reads need a subscription ID fromget_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_lookupwas only called with an empty request body.Only the
usregion has been tested.The legacy ConnectWise API is out of scope.
Development
npm testRuns 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 totest/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, andstore.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.tsandsrc/remote/: an MCP server over Streamable HTTP.
The HTTP server (self-hosting)
npm run build && npm run start:remoteIt 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 |
|
|
| For |
| For |
| Optional key prefix (default |
Licence
MIT. See LICENSE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Hosted remote MCP for protected account access, permissions, activity history and supported undo.
Managed MCP gateway with OAuth, per-agent permissions, shared accounts and activity logs.
One MCP URL for all your connectors — scoped writes, enforced constraints, and a full audit trail.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables 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 npm1MIT
- AlicenseNot gradedqualityFmaintenanceEnables 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

magicsword-mcpofficial
AlicenseAqualityBmaintenanceEnables 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.26263 npmApache 2.0- AlicenseNot gradedqualityCmaintenanceTurns 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 npmMIT