关于 ConnectWise PSA
ConnectWise PSA 是面向使用 ConnectWise PSA (Manage) 的技术人员、调度员和财务人员的 MCP 服务。可配置工具集涵盖工单、工时、排程、公司记录、设备配置和发票;本地部署还可选用只读 SQL 报表功能。
主要功能
- 01管理工单、备注和状态
- 02记录工时并提交工时表
- 03搜索公司、联系人和资产
- 04查看排程和成员可用情况
- 05读取发票与协议
- 06可选只读 SQL 报表
适用场景
- 01查看和更新服务或项目工单
- 02记录工单工时并提交工时表
- 03依据成员可用情况协调调度
- 04核查发票和未开票工时
MCP 相关
该 MCP 服务以可配置工具集提供 ConnectWise PSA 功能,并支持 stdio 和 streamable HTTP 传输。会话可提供各自成员的 API 密钥;本地部署也可启用只读 SQL 工具集。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y mcp-connectwise-psaCW_SITEConnectWise host (e.g. na.myconnectwise.net or an on-prem host; full URLs accepted)CW_COMPANY_IDConnectWise login company idCW_CLIENT_IDIntegration clientId from developer.connectwise.comCW_PUBLIC_KEY密钥API member public keyCW_PRIVATE_KEY密钥API member private keyCW_MEMBER_IDENTIFIERMember identifier the API keys belong to — enables "my tickets"/"my time" toolsCW_TOOLSETSComma list of toolsets/presets (default: all). Add sql for database queries.CW_DB_HOSTConnectWise SQL Server host (on-prem only) — enables the opt-in sql toolsetCW_DB_NAMEConnectWise Manage database, e.g. cwwebapp_acmeCW_DB_USERDedicated read-only database login (db_datareader)CW_DB_PASSWORD密钥Password for the read-only database loginCW_DB_QUERY_LIBRARYPath to a writable JSON file holding saved SQL queries本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
41收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| board | string | 否 | 服务工作板名称(例如 "Help Desk") |
| status | string | 否 | 状态名称(例如 "New"、"In Progress") |
| open_only | boolean | 否 | 仅显示未关闭的工单(默认 true) |
| page_size | integer | 否 | 每页结果数(默认 25,最大 1000) |
| company_id | integer | 否 | 按公司 ID 筛选 |
| assigned_to | string | 否 | 分配给工单的成员标识符 |
| page_number | integer | 否 | 页码(默认值为 1) |
| ticket_type | enum | 否 | 要包含的工单类型:service、project 或两者(默认两者)both | service | project |
| company_name | string | 否 | 按公司名称精确筛选 |
| response_format | enum | 否 | 输出格式:人类可读的 Markdown(默认)或结构化 JSONmarkdown | json |
| summary_contains | string | 否 | 工单摘要包含的文本 |
详细介绍
mcp-connectwise-psa
适用于 ConnectWise PSA(Manage)的 MCP(Model Context Protocol)服务 — 精选了涵盖 8 个工具集的工具,面向技术人员、调度员和账单人员;此外还提供用于访问 API 其他功能的备用入口,以及适用于本地部署的只读 SQL 工具集,让 AI 助手能够按照不同角色的工作方式使用 PSA:
- 工单 — 搜索 / 我的工单 / 完整详情,创建工单,更新状态 / 优先级 / 负责人,添加讨论 / 内部备注,还可发现看板·状态·优先级,并查看每张工单的工时和任务。涵盖服务工单和项目工单 — ConnectWise 将它们保存在不同的资源中,因此读取工具会同时查询两者,而按 ID 查询的工具会检测 ID 所属的类型
- 工时 — 将工时记录到工单(包含工作角色、工作类型,以及 CW 的休息时间扣除功能),查看自己的工时,查询工作角色和工作类型,以及查看和提交工时表
- 公司和联系人 — 快速查找、联系人详情(电话 / 邮箱)、公司站点
- 配置项 — 设备 / 资产的序列号、IP、操作系统和保修信息(只读)
- 调度 (排程) — 排程条目(列表 / 我的 / 创建 / 重新排程 / 取消),以及成员的时区、工作时间和空闲 / 已预订状态
- 开票 (财务,只读) — 发票、协议,以及可开票但尚未开票的工时
- 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 成员(集成账户)中创建。
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 本身负责:成员的安全角色决定哪些操作能够成功,且每条备注和时间记录都会归属到该成员名下。
在初始化请求(以及会话中的每个后续请求)中发送密钥:
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_bundle_tickets、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_work_types、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: dispatch或x-cw-toolsets: tech,finance。 - stdio — 使用
CW_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 提供了非规范化的 v_rpt_* 视图,其中已将服务板、状态、公司和联系人关联到记录上,例如 v_rpt_service、v_rpt_time、v_rpt_company、v_rpt_invoices、v_rpt_agreementlist。cw_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_datareader 角色中;对其他所有操作(EXECUTE、所有写入、DDL、BACKUP)执行 DENY,并对其发现的所有类似凭据的列执行 SELECT 的 DENY——这些列名会随 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_cmdshell、sp_OACreate、sp_send_dbmail,以及用于捕获 NTLM 凭据的xp_dirtree。无需 EXECUTE 权限,OPENROWSET/BULK INSERT也能读取文件,因此还必须关闭 Ad Hoc Distributed Queries。
运维建议:优先使用可读的 AG 辅助副本或还原后的报表副本,而非生产主副本;将 SQL 端口的防火墙访问限制为仅允许 MCP 主机;并为此登录账户启用 SQL Audit 或 Extended Events 会话。
配置参考
| 变量 | 默认值 | 用途 |
|---|---|---|
CW_SITE | — | ConnectWise 主机(云端或本地部署;接受完整 URL) |
CW_COMPANY_ID | — | 登录公司 ID |
CW_CLIENT_ID | — | 集成 clientId |
CW_PUBLIC_KEY / CW_PRIVATE_KEY | — | API 成员密钥——stdio 必需;HTTP 不使用(BYOK) |
CW_MEMBER_IDENTIFIER | — | stdio 密钥所属的成员(my-tickets/my-time) |
TRANSPORT / PORT | stdio / 3000 | 传输方式选择 |
CW_TOOLSETS | all | 已启用的工具集(键/预设);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 的不同资源中。读取工具接受
ticket_type(默认为both),并会合并结果;按 ID 查询的工具默认为auto,会检测资源,因此会多进行一次查询——传入service/project可跳过检测。cw_create_ticket仅创建服务工单:项目工单需要指定项目和阶段。 - 已记录时段中的休息时间应填写在
hours_deduct中,time_end保持为实际结束时间。若改为传入缩短后的hours,ConnectWise 会显示一个实际并未发生的结束时间。 - 时间戳必须精确到整秒——服务端会进行规范化处理(ConnectWise 不接受小数秒)。
- 时间条目要求 ConnectWise 中存在覆盖该条目日期的开放时间报告周期;若不存在,API 的消息会直接传回。
- 某些本地部署版本缺少
/system/myAccount——对于“我的工单”/“我的时间”,请显式提供成员标识符(CW_MEMBER_IDENTIFIER或x-cw-member-id)。 - 讨论备注对客户可见;内部备注则不可见——工具会明确区分。时间条目的备注可以复制到工单的讨论(
add_to_detail)、内部分析(add_to_internal)、解决方案(add_to_resolution)中,也可以不复制;结果会说明复制到了哪里。请注意,三项都关闭时,备注仍保留在时间条目中,并不意味着它会变成内部备注。 cw_db_query会在达到max_rows(默认值为 200)或约 20,000 个字符的上限时停止,并在服务端取消查询;响应会说明触发了哪个限制。每次查询的默认期限为 30 秒,最长为 120 秒。- 数据库连接以 READ UNCOMMITTED 模式读取,避免报告扫描阻塞技术人员保存工单。代价是可能出现脏读:有并发写入时,计数只是近似值。如果报告必须精确,请设置
CW_DB_READ_UNCOMMITTED=false。 - 对含有 DENY 权限列的表执行
SELECT *会失败——请明确指定所需列。 - 云托管的 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/
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。