Skip to main content
Glama
mspstack

mcp-connectwise-psa

by mspstack

mcp-connectwise-psa

一个用于 ConnectWise PSA (Manage) 的 MCP (Model Context Protocol) 服务器 — 覆盖 8 个工具集的精选工具,涵盖技术人员、调度员和计费,外加一个用于其余 API 的逃生舱和一个用于本地部署的只读 SQL 工具集,使 AI 助理能够像每个角色一样使用 PSA:

  • 工单 — 搜索 / 我的工单 / 含备注的完整详情,创建,更新状态/优先级/负责人,添加讨论/内部备注,外加看板·状态·优先级发现以及每张工单的时间和任务

  • 时间 — 针对工单记录时间,查看自己的时间,工作角色查询,以及列出并提交时间表

  • 公司与联系人 — 快速查找,联系人详情(电话/电子邮件),公司站点

  • 配置 — 带序列号、IP、操作系统、保修信息的设备/资产(只读)

  • 调度 (schedule) — 计划条目(列表/我的/创建/重新安排/取消),以及成员及其时区、工作时间和空闲/已预订可用性

  • 开票 (finance, 只读) — 发票、协议,以及随时可开票的未开票计费时间

  • SQL (仅限本地部署) — 直接针对 cwwebapp_* Manage 数据库执行只读 T-SQL,用于 REST 无法表达的跨表报表,附带可搜索的架构目录和一个助手可以不断扩充的已保存查询库。通过配置 CW_DB_* 启用;一旦启用,每个未收窄工具集的会话都会拥有它

  • 工具集与角色预设 — 通过 x-cw-toolsets 标头(或 CW_TOOLSETS)仅启用会话所需的功能;预设 tech / dispatch / invoicing / all。默认是 all — 当需要更小的工具面时,可按会话收窄。每个工具还会将其工具集报告为 _meta.group,因此聚合器(MSPStack 网关)可以按能力对工具进行分组和切换

  • 按成员 API 密钥 (BYOK) — 每个用户提供自己的 ConnectWise 成员密钥;ConnectWise 强制执行该成员的安全角色,并且每次写入都归属于实际人员

  • 传输方式 — 本地使用 stdio,共享部署使用 streamable HTTP;包含 Docker 镜像

快速开始(本地,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=jdoe \
node dist/index.js

Claude Desktop / Claude Code 配置:

{
  "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": "jdoe"
      }
    }
  }
}

ConnectWise API 要求提供 clientId — 在 developer.connectwise.com 注册一个(免费)集成。API 成员密钥在 ConnectWise 中创建,路径为 我的账户 → API 密钥(按成员)或 系统 → 成员 → API 成员(集成账户)。

Related MCP server: superops-mcp

HTTP 部署

CW_SITE=… CW_COMPANY_ID=… CW_CLIENT_ID=… \
node dist/index.js --transport http --port 3000

或使用 Docker:docker build -t mcp-connectwise-psa . && docker run -p 3000:3000 -e CW_SITE -e CW_COMPANY_ID -e CW_CLIENT_ID mcp-connectwise-psa

路由

用途

POST/GET/DELETE /mcp

MCP streamable-http 端点

GET /health

存活探针

会话保存在内存中 — 请运行单个实例(或使用粘性会话)。

访问控制 — 自带密钥 (BYOK)

在 HTTP 上没有 MCP 级别的角色系统。每个会话出示自己的 ConnectWise 成员 API 密钥,ConnectWise 本身就是访问控制:成员的安全角色决定哪些操作成功,每条备注和时间条目都归属于该成员。

在 initialize 请求中发送你的密钥(以及会话中的每个后续请求):

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")
  • 没有密钥的请求将被拒绝并返回 401;两个密钥标头必须同时提供。

  • 密钥永远不会被记录。会话绑定到密钥对的 SHA-256 哈希;在同一会话 ID 上出示不同的密钥对 → 403

  • 在 ConnectWise 中通过 我的账户 → API 密钥 创建成员 API 密钥。每个技术人员使用自己的密钥。

本地 stdio 是单用户的,使用环境变量 CW_PUBLIC_KEY/CW_PRIVATE_KEY 而不是标头。

工具集

工具被分组到工具集中,这样会话只能看到它所需的能力 — 调度员不需要开票工具,小的工具面可以让助手保持专注(并且其上下文成本更低)。写入是否真正成功仍然由成员的 ConnectWise 安全角色决定。

工具集键

工具

tickets

cw_search_tickets, cw_my_tickets, cw_get_ticket, cw_create_ticket, cw_update_ticket, cw_add_ticket_note, cw_list_boards, cw_get_board, cw_list_priorities, cw_list_ticket_time, cw_list_ticket_tasks

time

cw_create_time_entry, cw_update_time_entry, cw_list_my_time, cw_list_work_roles, cw_list_my_timesheets, cw_submit_timesheet

companies

cw_search_companies, cw_get_company, cw_search_contacts, cw_get_contact, cw_list_company_sites

configurations

cw_list_configurations, cw_get_configuration

schedule

cw_list_schedule_entries, cw_my_schedule, cw_schedule_ticket, cw_update_schedule_entry, cw_delete_schedule_entry, cw_member_availability, cw_list_members, cw_get_member

finance

cw_list_invoices, cw_get_invoice, cw_list_agreements, cw_get_agreement, cw_list_unbilled_time

advanced

cw_find_endpoint(搜索完整的 CW API — ~1,150 个端点)、cw_get(对任意路径执行只读 GET)

sql (仅本地部署,需要 CW_DB_*)

cw_db_query(只读 T-SQL)、cw_db_find_table(架构目录)、cw_db_find_query / cw_db_save_query(已保存查询库)

预设按角色捆绑键:tech = tickets + time + companies + configurations · dispatch = tickets + schedule + companies + configurations · invoicing = finance + time + companies · all = 所有键。角色预设刻意排除 sql — 技术人员工具面不是数据库工具面。

advanced 工具集是逃生舱(在 all 中,但不在任何角色预设中):cw_find_endpoint 搜索捆绑的完整 ConnectWise API 目录,cw_get 对任意路径执行只读 GET — 因此助手可以触及精选工具未包裹的长尾(采购、销售、项目、系统…)。要移除它,请改为指定键或角色预设(x-cw-toolsets: tech)。

使用逗号列表选择工具集,可混合键和预设:

  • HTTP — 每个会话的 x-cw-toolsets 标头:x-cw-toolsets: dispatchx-cw-toolsets: tech,finance

  • stdioCW_TOOLSETS 环境变量或 --toolsets 标志:CW_TOOLSETS=invoicing

默认是 all 预设 — 服务器配置了的所有能力;想要更小工具面的客户端会指定它需要的键或角色。CW_TOOLSETS/--toolsets 中的未知键会快速失败;x-cw-toolsets 标头中的未知令牌会被忽略。唯一的破坏性工具是 cw_delete_schedule_entry(dispatch);finance 是只读的。cw_db_save_query 会写入,但只写入查询库文件 — 数据库访问本身通过授权仅为 SELECT。

例外:sql 工具集

其他每个工具集都使用调用者自己的 ConnectWise 密钥运行,因此 ConnectWise 会过滤返回的内容。sql 则不然:它通过服务器范围的只读登录读取数据库,因此其结果不归属于任何成员,也不会被该成员的安全角色、看板限制或记录权限过滤。

因此,配置 CW_DB_* 才是关键决定。一旦服务器配置了数据库,sql 就是一个普通键:它在 all 中,在默认选择中,并且每个未收窄工具集的会话都可以读取整个 PSA 数据库。没有 CW_DB_* 的服务器会静默地移除它,因此从不想要它的部署不会出任何问题。

如果你需要让某些调用者而不是其他调用者访问数据库,请按会话执行(x-cw-toolsets: tech)或在服务器前面执行 — 聚合网关可以分别对 cw_db_* 工具分层。在服务器端限制损害的是登录:请参阅下面的运行手册,并将其保持为 db_datareader,同时拒绝凭据列。

SQL 工具集(本地部署数据库)

云托管的 ConnectWise 不提供数据库访问权限,因此此工具集仅适用于本地部署。请使用专门为此目的创建的登录,将其指向 Manage 数据库:

CW_DB_HOST=sqlhost CW_DB_NAME=cwwebapp_acme \
CW_DB_USER=cw_mcp_ro CW_DB_PASSWORD=… \
CW_DB_QUERY_LIBRARY=/data/cw-queries.json \
node dist/index.js

这就是全部:配置了数据库后,sql 工具集就成为默认选择的一部分。如果没有 CW_DB_* 却显式指定 sql,启动时会失败(而像 all 这样仅包含它的选择会被剪除)。在会话真正使用工具之前,不会连接到数据库。

从报表视图开始。 ConnectWise 附带反规范化(denormalized)的 v_rpt_* 视图,这些视图已经将看板、状态、公司和联系人联接到记录上 — v_rpt_servicev_rpt_timev_rpt_companyv_rpt_invoicesv_rpt_agreementlistcw_db_find_table 知道这些视图及其背后的基础表;它只携带关键列,因为确切的列列表只需一次 INFORMATION_SCHEMA 查询即可获得,并且对于你的版本来说始终是正确的。

已保存查询库是已提交的核心加上位于 CW_DB_QUERY_LIBRARY 的可写覆盖层(JSON,{ version, queries[] })。覆盖层条目按 slug 优先,cw_db_save_query 会追加到其中,scripts/import-queries.mjs 从现有的 BrightGauge 导出中填充它:

node scripts/import-queries.mjs /path/to/brightgauge-export

导入的查询保留在此存储库之外 — 它们是你的报表,可能包含公司名称和费率。在容器上,将 CW_DB_QUERY_LIBRARY 指向挂载的存储,否则已保存的查询会随容器一起消亡。

登录就是安全边界

没有语句验证:服务器按原样将模型的 SQL 发送给 SQL Server,因此登录被允许做什么,就恰好可能发生什么。两个脚本负责设置并证明这一点。

创建它 — 编辑顶部的四个变量,以 sysadmin 身份运行。@WhatIf 默认为 1,因此第一次运行只打印计划:

sqlcmd -S SQLHOST\CWPROD -d master -i scripts/create-readonly-login.sql

它创建的登录不归属任何服务器角色,将其添加到某个数据库的 db_datareaderDENY 其他所有权限(EXECUTE、所有写入、DDL、BACKUP),并对其发现的每个看似凭据的列 DENY SELECT — 这些列名会随 Manage 版本变化,而且每个 MSP 都会添加自己的列,因此通过发现而非硬编码来找到它们。重新运行是安全的,也是在升级添加表后重新应用 DENY 的方式。它会报告必须关闭但从不更改的实例级设置:禁用 xp_cmdshell 可能破坏其他应用程序,因此这仍然是一个决策。

验证它 — 使用新的登录身份,而不是管理员身份:

sqlcmd -S SQLHOST\CWPROD -d cwwebapp_acme -U cw_mcp_ro -P '<password>' -i scripts/verify-readonly-login.sql

每项检查都会输出 PASS 或 FAIL:SELECT 可正常使用,UPDATE/CREATE TABLE 被拒绝(在一个始终回滚的事务中执行,以防因缺少 DENY 而导致实际写操作发生),xp_cmdshell/sp_OACreate/OPENROWSET(BULK …) 不可达,凭据列不可读,且登录名未处于任何高风险角色中。只要是 FAIL 就代表当下不应启用该工具集。

先了解两个重要后果:

  • SELECT * 在含被拒列的任意表上都会失败,而不是返回其余列。这正是有意为之;工具的错误信息会提示模型指定所需的列名。

  • EXECUTE 权限才是关键权限。 拥有该权限后,“只读 SQL”会变成以 SQL Server 服务账户身份执行的远程代码执行——xp_cmdshellsp_OACreatesp_send_dbmail,以及用于 NTLM 捕获的 xp_dirtreeOPENROWSET/BULK INSERT 在完全不需要 EXECUTE 权限的情况下即可读取文件,因此 Ad Hoc Distributed Queries(Ad Hoc 分布式查询)也必须关闭。

操作层面建议:优先使用可读的 AG 辅助数据库副本或当前生产环境已恢复的报表副本;将 SQL 端口访问限制为仅 MCP 主机可访问;并针对此登录名启用 SQL Audit 或 Extended Events 会话。

配置参考

Variable

Default

Purpose

CW_SITE

ConnectWise 主机(云或本地部署;接受完整 URL)

CW_COMPANY_ID

登录公司 ID

CW_CLIENT_ID

集成 clientId

CW_PUBLIC_KEY / CW_PRIVATE_KEY

API 成员密钥 — stdio 必需;HTTP(自带证书)不使用

CW_MEMBER_IDENTIFIER

stdio 密钥所属的成员(my-tickets/my-time)

TRANSPORT / PORT

stdio / 3000

传输选择

CW_TOOLSETS

all

启用的工具集(keys/预设);HTTP 可通过 x-cw-toolsets 按会话覆盖

CW_DB_HOST

ConnectWise SQL Server 主机,或 host\INSTANCE — 即启用 sql 工具集

CW_DB_NAME / CW_DB_USER / CW_DB_PASSWORD

数据库及其专用只读登录(四项必须同时提供)

CW_DB_PORT

1433

TCP 端口;与无实例名同时使用时不生效

CW_DB_ENCRYPT / CW_DB_TRUST_SERVER_CERT

true / true

TLS,以及接受本地站点常见的自签名证书

CW_DB_READ_UNCOMMITTED

true

以 READ UNCOMMITTED 读取,避免报表扫描阻塞生产库的写操作

CW_DB_QUERY_TIMEOUT_MS / CW_DB_MAX_ROWS

30000 / 200

每次查询的截止时间和行数上限

CW_DB_QUERY_LIBRARY

可写已保存查询文件路径;未设置 ⇒ 仅内置查询,不提供保存工具

说明与限制

  • 工单搜索默认为开放工单;状态 / 看板名称需要精确匹配,基于文本的过滤器使用子串匹配。

  • 时间戳必须带整秒——服务器会进行格式化(ConnectWise 不接受含小数的秒)。

  • 时间条目要求在 ConnectWise 中,该日期必须对应一个处于打开状态的时间报告周期;若不存在该周期,API 的提示信息会被原样透传。

  • 部分本地版本未提供 /system/myAccount——对于“my tickets” / “my time”,需要显式提供成员标识符(CW_MEMBER_IDENTIFIERx-cw-member-id)。

  • 讨论备注对客户同步可见;内部备注对客户不可见——工具本身会明确区分这一点。

  • cw_db_query 在达到 max_rows(默认 200)或约 20,000 字符预算限制时终止,并会从服务端取消该查询;响应中会说明当前命中哪个限制。单次查询默认超时时间为 30 秒,最长不超过 120 秒。

  • 数据库连接使用了 READ UNCOMMITTED 读级别,以避免报表扫描阻塞验证人员保存工单。代价是可能读到脏数据:在并发写入时,计数结果会不准。如需精确报表,请将 CW_DB_READ_UNCOMMITTED 设为 false

  • SELECT * 在任意包含 DENY 列的表上都会失败——请明确列出所需列名。

  • 云端托管的 ConnectWise 实例没有数据库访问权限;sql 工具集仅限本地部署。

开发

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

语 .

MIT

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
4dRelease cycle
11Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    MCP server for SolarWinds Service Desk (SWSD/Samanage) enabling reading and modifying tickets, comments, knowledge-base articles, and more via each user's own API token.
    37
    93
    3
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP Server for agents to onboard, pay, and provision services autonomously with InFlow

  • A paid remote MCP for ClawManager, built to return verdicts, receipts, usage logs, and audit-ready J

  • MCP server for Appcircle mobile CI/CD platform.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mspstack/mcp-connectwise-psa'

If you have feedback or need assistance with the MCP directory API, please join our Discord server