Skip to main content
Glama
mspstack

mcp-connectwise-psa

by mspstack

mcp-connectwise-psa

MCP-сервер (Model Context Protocol) для ConnectWise PSA (Manage) — подобранные инструменты из 8 наборов, закрывающие задачи техников, диспетчеров и выставления счетов, плюс запасной выход на остальную часть API и набор SQL только для чтения для локальных (on-prem) развертываний — чтобы ИИ-ассистент работал с PSA так, как с ней работает каждая роль:

  • Заявки — поиск / мои заявки / полная детализация с заметками, создание, изменение статуса/приоритета/ответственного, добавление обсуждений и внутренних заметок, а также получение списка досок·статусов·приоритетов и времени и задач по конкретной заявке

  • Время — списание времени по заявкам, просмотр собственного времени, поиск рабочих ролей и просмотр и отправка своих табелей учета времени

  • Компании и контакты — быстрый поиск, подробная карточка контакта (телефоны/эл. почта), площадки компаний

  • Объекты — устройства/активы с серией, IP, ОС и гарантийной сроком (только центральный доступ)

  • Диспетчеризация (расписание) — записи расписания (список/мои/создание/перенос/отмена), а также участники с часовым поясом, рабочими часами и доступностью «свободен/занят»

  • Выставление счетов (финансы, только чтение) — счета, агрехи и невыставленные оплачиваемые часы, готовые к выставлению

  • SQL (только on-prem) — T-SQL только для чтения напрямую против базы Manage cwwebapp_* для межтабличной отчетности, которую REST не может выразить; в комплекте — каталог схемы с поиском и библиотека сохраненных запросов, которую ассистент может пополнять. Включается настройкой CW_DB_*; если она задана, каждая сессия, которая не сужает свои наборы, имеет этот набор

  • Наборы и роли — возможность настроить только нужное для сессии через заголовок x-cw-toolsets (или CW_TOOLSETS); пресеты tech / dispatch / invoicing / all. По умолчанию — all; сузите его для сессии, если нужен маленький набор кода. Каждый инструмент также передает свой набор в виде _meta.tool, поэтому агрегатор (шлюз MSPMSP) может группировать и переключать инструменты по возможности

  • Свои API-ключи участника (BYOK) — каждый пользователь приносит свои ключи участника ConnectWise; ConnectWise сам применяет роль безопасности этого участника, и каждая запись приписывается конкретному человеку

  • Транспорты — STDIO для локального использования, streamable HTTP для общих развертываний; включая Docker-образ

Quick start (локальный, 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"
      }
    }
  }
}

Коллизии clientId требует API ConnectWise — зарегистрируйте (бесплатную) интеграцию на developer.connectwise.com. Ключи API-участника создаются в ConnectWise в разделе My Account → API Keys (для каждого участника) или System → Members. API Members (интеграционные записи).

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

Проверка живости (liveness)

Все сессии хранятся в памяти — запускайте один экземпляр сервера (или используйте липкие сессии).

Управление доступом — со своими ключами (BYOK)

Пов HTTP не имеет системы ролей на уровне MCP. Каждая сессия передает свои ключи участника ConnectWise, и контроль доступа осуществляет сам 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-хэшу пары ключей; предоставление другой пары в том же идентификаторе session → 403 .

  • Создавайте API-ключи участника в ConnectWise в разделе My Account → API Keys. Каждый участник техникой использует свой.

Локальный stdio — однопользовательский и использует переменные окружения CW_PUBLIC_KEY/CW_PRIVATE_KEY вместо заголовков.

Наборы инструментов

Инструменты сгруппированы в наборы инструментов (toolsets), чтобы сессия видела только нужные возможности: диспетчеру не нужны средства выставления счетов, а маленькая поверхность поддерживает фокус (и дешевле контекст ассистента). Управление на возникающие возможности по-прежнему определяется ролью безопасности участника во 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

scheduled

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 (поистр по всему API CW — ~1,150 конечноtut), cw_get (только чтение GET по любому пути)

sql (on-prem, требует 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 только для чтения к любому пути — так ассистент может достичь "длинный хвост" (procurement, sales, projects, system…), который и текущие инструменты не охватывают. Чтобы исключить его, укажите вместо него ключи или ролевые пресеты — например, x-cw-toolsets: tech.

Выбирайте наборы с списком через коммуник, смешивая ключи и пресеты:

  • HTTP — заголовок x-cw-toolsets для каждой сессии: x-cw-toolsets: dispatch, or x-cw-toolsets: tech,finance.

  • stdio — переменная окружения CW_TOOLSETS или флаг --toolsets: CW_TOOLSETS=invoicing.

По умолчанию — пресет all — все возможности, которые сервер настроен обрабатывать; клиент, который хочет меньший набор, называет нужные ему ключи или персона. Неизвестные ключи в CW_TOOLSETS/--toolsets приводят к быстрому завершению; неизвестные токены в заголовке x-cw-toolsets наверное и игнорируются. Единственный разрушающий инструмент — cw_delete_schedule_entry (dispatch); финансы — только на чтение. Инстро cw_db_save_query записывает данные, но только в файла библиотеки запросов: доступом к базе разрешен только SELECT по грантам.

Исключение: набор sql

Каждый остальной набор работает получения собственными ключами ConnectWise вызывающего, поэтому на ошибку фильтрации налагается. А вот набор sql — нет: он читает базу через серверный логин только для чтения, поэтому результаты не приписываются участнику и не уфильтруются его ролью безопасности, ограничниями по доскам или правами записей.

Поэтому настройка CW_DB_* — это важное решение. Как только на сервере есть база, sql становится обычным ключом: он входит в all, он входит в выбор по умолчанию, и каждая сессия, которая не сужает свои наборы инструментов, может прочитать всю базу PSA. Сервер без настройки CW_DB_* просто отбрасывает sql молча, так что в развертываниях, которые этого не хотели, ничего не ломается.

Если вам нужен доступ к базе для одних вызывающих, но не для других, делайте это по сессии (x-cw-toolsets: tech) или перед сервером — экскаются на шлюзе могут разделять cw_* инструменты по уровням. Что ограничивает ущерб на стороне сервера — это сам логин: смотрите у ниже в руководстве, и держите его ролью db_datareader с закрытием колонок с учетными данными.

SQL набор (база данных только для локального размещения)

Облачная ConnectWise не дают доступа к базе данных, поэтому этот набор — только для локали развернуть (on-prem). Направьте его на базу 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 входит в выбор по умолчанию. Если явно указать sql без CW_DB_*, запуск вызовет ошибку (а выбор, который лишь включает его, как all, молча сокращается). Никакое соединение с базой не происходит, hasta пока сессия не использует инструмент.

Начните с отчётовых представлений. ConnectOftenes постаставляет денормализованные представления v_rpt_*, которые уже связывают доски, статус, компанию и контакт с записью — v_rpt_service, v_rpt_time, v_rpt_company, v_rpt_invoices, v_rpt_greementlist. cw_db_find_table знает те представления и базовые таблицы за ними и несёт только ключевые поля, поскольку точный список полей — это один запрос к INFORMATION_SCHEMA, и он всегда верен для вашей версии.

Библиотека сохраненных запросов — это commit в репозитории единственное ядро plи запись-в к файл-наложение, указанный в 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 как есть, поэтому логин имеет ровно те права, которые реально могут выполнить. Два скрипта настраивают и подтvely.

Создание — правьте четыре переменные в начале, запустите как sysadmin. @WhatIf = 1 by default, so the first run only печатает план:

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

ok создает логин без каких-либо ролей сервера, добавляет в db_datareader в одной базе, дает DENY для всего остального (EXECUTE, все записи, DDL, BACKUP) и выдает DENY SELECT on все похожие на учётные данные поля, которые обнаруживают — названия меняются между версиями Manage, и каждый MSP добавляет свои, так что они находятся, а не захардкожены. Повторный запуск безопасен; так вы заново применяете DENY после за upgrade, который добавил таблицы. Скрипт сообщает об инстанс-wide параметрах, которые должны быть выключены, но никогда их не меняет: отключение xp_cmdshell может сломать другие приложения, поэтому это остаёт администtake.

Проверка — от имени нового логина, не как admin:

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 — вот разрешение, которое имеет значение. При нём «read-only SQL» превращается в удалённое выполнение кода от имени учётной записи службы SQL Server: xp_cmdshell, sp_OACreate, sp_send_dbmail, xp_dirtree — для перехвата NTLM. OPENROWSET/BULK INSERT читают файлы вообще без EXECUTE, поэтому Ad Hoc Distributed Queries тоже должны быть выключены.

С эксплуатационной точки зрения: на отчётность берите читаемую вторичную реплику группы доступности или восстановленную копию, а не основной экземпляр прода, доступ к SQL-порту ограничьте межсетевым экраном по MCP-хосту и держите на этом логине сеанс SQL Audit или Extended Events.

Справочник по конфигурации

Переменная

По умолчанию

Назначение

CW_SITE

—

Хост ConnectWise (облачный или локальный; принимаются полные URL)

CW_COMPANY_ID

—

company 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

—

Хост SQL Server ConnectWise или 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; также принимается типовой самоподписанный локальный сертификат (on-prem)

CW_DB_READ_UNCOMMITTED

true

Чтение на READ UNCOMMITTED, чтобы отчётные запросы никогда не блокировали проводящие запись процессы прода

CW_DB_QUERY_TIMEOUT_MS / CW_DB_MAX_ROWS

30000 / 200

Предел времени на запрос и максимальное количество строк

CW_DB_QUERY_LIBRARY

—

Путь к файлу сохраняемых запросов с правом записи; не задан ⇒ только встроенные запросы, инструмента сохранения нет

Notes & limits

  • Поиск тикетов по умолчанию ищет среди открытых тикетов; имена статусов и досок должны задаваться точно, текстовые фильтры работают по подстроке.

  • В метках времени должны быть целые секунды — сервер сам приводит их к такому виду (ConnectWise отклоняет доли секунды).

  • Для записей времени требуется открытый отчётный период времени в ConnectWise на указанную дату; когда его нет, передаётся сообщение API.

  • На некоторых локальных версиях /system/myAccount отсутствует — передавайте идентификатор участника явно (CW_MEMBER_IDENTIFIER или x-cw-member-id) для «my tickets»/«my time».

  • Заметки обсуждения видны клиенту, а внутренние — нет: инструмент явно это указывает.

  • cw_db_query останавливается после max_rows (по умолчанию 200) или по бюджету в 20 000 символов; отменой и запрос на стороне сервера происходит с указанием лимита — эта информация попадает к клиенту. Дедлайн по умолчанию — 30 с, максимум 120 с.

  • Подключение к базе данные читает на уровне READ UNCOMMITTED, чтобы сканирование отчёта не блокировало сохранение тикета специалистом. Цена этого — «грязные» чтения: при параллельной записи подсчёты выходят приблизительными. Установите CW_DB_READ_UNCOMMITTED=false, если отчёт должен быть точным.

  • SELECT * не будет работать на таблице с запрещённым столбцом — перечисляйте нужные вам столбцы.

  • В облачных экземплярах ConnectWise нет доступа к базе данных; набор инструментов sql работает только на локальных установках.

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    An MCP server for SuperOps PSA/RMM, enabling MSPs to manage tickets, assets, clients, and field technician operations through SuperOps's API.
    22
    3
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server for Kaseya BMS PSA — tickets, accounts, time entries, and contracts. Enables AI assistants to manage service desk operations via the Kaseya BMS API.
    Apache 2.0
  • 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
    557 npm
    4
    MIT