Skip to main content
Glama
mspstack

mcp-connectwise-psa

by mspstack

mcp-connectwise-psa

Un servidor MCP (Model Context Protocol) para ConnectWise PSA (Manage): herramientas seleccionadas en 8 conjuntos de herramientas que cubren a técnicos, despachadores y facturación, además de una vía de escape para el resto de la API y un conjunto de herramientas SQL de solo lectura para implementaciones locales, de modo que un asistente de IA trabaje con PSA como lo haría cada rol:

  • Tickets — búsqueda / mis tickets / detalle completo con notas, crear, actualizar estado/prioridad/propietario, añadir notas de discusión/internas, además de descubrimiento de tableros·estados·prioridades y tiempo y tareas por ticket

  • Tiempo — registrar tiempo en tickets, revisar tu propio tiempo, consulta de roles de trabajo, y listar y enviar tus hojas de horas

  • Empresas y contactos — búsqueda rápida, detalle de contacto (teléfonos/correos), sedes de empresa

  • Configuraciones — dispositivos/activos con números de serie, IP, SO, garantía (solo lectura)

  • Despacho (horario) — entradas de horario (listar/mías/crear/reprogramar/cancelar), y miembros con su zona horaria, horario laboral y disponibilidad libre frente a reservada

  • Facturación (finanzas, solo lectura) — facturas, acuerdos y tiempo facturable no facturado listo para facturar

  • SQL (solo local) — T-SQL de solo lectura directamente contra la base de datos de Manage cwwebapp_* para los informes entre tablas que REST no puede expresar, con un catálogo de esquema buscable y una biblioteca de consultas guardadas que el asistente puede ampliar. Se habilita configurando CW_DB_*; donde esté, cada sesión que no restrinja sus conjuntos de herramientas lo tendrá

  • Conjuntos de herramientas y perfiles — active solo lo que una sesión necesite mediante la cabecera x-cw-toolsets (o CW_TOOLSETS); ajustes predefinidos tech / dispatch / invoicing / all. El valor predeterminado es all — redúzcalo por sesión cuando se desee una superficie menor. Cada herramienta también informa de su conjunto como _meta.group, de modo que un agregador (la pasarela MSPStack) pueda agrupar y cambiar de herramientas según la capacidad

  • Claves de API por miembro (BYOK) — cada usuario aporta sus propias claves de miembro de ConnectWise; ConnectWise aplica el rol de seguridad de ese miembro, y cada escritura se atribuye a la persona real

  • Transportes — stdio para uso local, HTTP transmisible para implementaciones compartidas; imagen de Docker incluida

Inicio rápido (local, 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

Configuración de 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 exige un clientId en la API: registre una integración (gratuita) en developer.connectwise.com. Las claves de miembro de la API se crean en ConnectWise en Mi cuenta → Claves de API (por miembro) o Sistema → Miembros → Miembros de API (cuentas de integración).

Related MCP server: superops-mcp

Implementación HTTP

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

O con 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

Ruta

Propósito

POST/GET/DELETE /mcp

Punto de conexión MCP streamable-http

GET /health

Sonda de actividad

Las sesiones se mantienen en memoria: ejecute una única instancia (o sesiones fijas).

Control de acceso: traiga sus propias claves (BYOK)

Por HTTP no hay ningún sistema de roles a nivel de MCP. Cada sesión presenta sus propias claves de miembro de ConnectWise, y es el propio ConnectWise el que actúa como control de acceso: el rol de seguridad del miembro decide qué se permite, y cada nota y entrada de tiempo se atribuye a ese miembro.

Envíe sus claves en la solicitud de inicialización (y en cada solicitud posterior de la sesión):

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")
  • Una solicitud sin claves se rechaza con 401; ambas cabeceras de clave son obligatorias a la vez.

  • Las claves nunca se registran. Una sesión se vincula a un hash SHA-256 del par de claves; presentar un par distinto en el mismo id de sesión → 403.

  • Cree claves de miembro de la API en ConnectWise en Mi cuenta → Claves de API. Cada técnico usa las suyas.

El stdio local es de un solo usuario y usa CW_PUBLIC_KEY/CW_PRIVATE_KEY del entorno en lugar de cabeceras.

Conjuntos de herramientas

Las herramientas se agrupan en conjuntos de herramientas para que una sesión solo vea las capacidades que necesita: un despachador no necesita las herramientas de facturación, y una superficie de herramientas pequeña mantiene al asistente centrado (y su contexto económico). Que una escritura tenga éxito o no lo sigue rigiendo el rol de seguridad del miembro en ConnectWise.

Clave del conjunto

Herramientas

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 (busca en toda la API de CW — ~1150 puntos de conexión), cw_get (GET de solo lectura en cualquier ruta)

sql (local, requiere CW_DB_*)

cw_db_query (T-SQL de solo lectura), cw_db_find_table (catálogo de esquema), cw_db_find_query / cw_db_save_query (biblioteca de consultas guardadas)

Ajustes predefinidos agrupan claves por perfil: tech = tickets + time + companies + configurations · dispatch = tickets + schedule + companies + configurations · invoicing = finance + time + companies · all = todas las claves. Los ajustes predefinidos de perfil excluyen deliberadamente sql: una superficie de técnico no es una superficie de base de datos.

El conjunto advanced es la vía de escape (está en all, pero en ningún ajuste predefinido de perfil): cw_find_endpoint busca en un catálogo integrado de toda la API de ConnectWise, y cw_get realiza un GET de solo lectura en cualquier ruta, de modo que el asistente pueda llegar a la larga cola (aprovisionamiento, ventas, proyectos, sistema…) que las herramientas seleccionadas no envuelven. Para eliminarlo, nombre las claves o un ajuste predefinido de perfil en su lugar (x-cw-toolsets: tech).

Seleccione conjuntos de herramientas con una lista separada por comas que mezcle claves y ajustes predefinidos:

  • HTTP — la cabecera x-cw-toolsets, por sesión: x-cw-toolsets: dispatch o x-cw-toolsets: tech,finance.

  • stdio — la variable de entorno CW_TOOLSETS o el indicador --toolsets: CW_TOOLSETS=invoicing.

El valor predeterminado es el ajuste predefinido all — toda la capacidad para la que esté configurado el servidor; un cliente que quiera una superficie menor nombra las claves o el perfil que necesite. Las claves desconocidas en CW_TOOLSETS/--toolsets fallan de inmediato; los tokens desconocidos en la cabecera x-cw-toolsets se ignoran. La única herramienta destructiva es cw_delete_schedule_entry (dispatch); finanzas es de solo lectura. cw_db_save_query escribe, pero en el archivo de la biblioteca de consultas: el acceso a la base de datos en sí es solo SELECT por concesión.

Excepción: el conjunto de herramientas sql

Cualquier otro conjunto de herramientas se ejecuta con las claves de ConnectWise del propio llamante, por lo que ConnectWise filtra lo que se devuelve. sql no: lee la base de datos mediante un inicio de sesión de solo lectura en todo el servidor, por lo que sus resultados no se atribuyen a un miembro ni se filtran por el rol de seguridad, las restricciones de tablero o los permisos de registro de ese miembro.

Por tanto, configurar CW_DB_* es la decisión que importa. Una vez que un servidor tiene una base de datos, sql es una clave normal: está en all, está en la selección predeterminada, y toda sesión que no restrinja sus conjuntos de herramientas puede leer toda la base de datos de PSA. Un servidor sin CW_DB_* la elimina silenciosamente, de modo que nada se rompe para las implementaciones que nunca la quisieron.

Si necesita acceso a la base de datos para algunos llamantes pero no para otros, hágalo por sesión (x-cw-toolsets: tech) o delante del servidor: una pasarela agregadora puede clasificar las herramientas cw_db_* por separado. Lo que limita el daño en el lado del servidor es el inicio de sesión: consulte el runbook a continuación y manténgalo en db_datareader con las columnas de credenciales denegadas.

Conjunto de herramientas SQL (base de datos local)

ConnectWise alojado en la nube no ofrece acceso a la base de datos, por lo que este conjunto de herramientas es solo para implementaciones locales. Apúntelo a la base de datos de Manage con un inicio de sesión creado precisamente para este fin:

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

Eso es todo: con una base de datos configurada, el conjunto de herramientas sql forma parte de la selección predeterminada. Nombrar sql sin CW_DB_* falla al inicio (una selección que solo lo incluya, como all, se elimina en su lugar). Nada se conecta a la base de datos hasta que una sesión usa realmente una herramienta.

Empiece por las vistas de informes. ConnectWise incluye vistas desnormalizadas v_rpt_* que ya unen tablero, estado, empresa y contacto a un registro: v_rpt_service, v_rpt_time, v_rpt_company, v_rpt_invoices, v_rpt_agreementlist. cw_db_find_table las conoce a ellas y a las tablas base que hay detrás; solo incluye columnas clave, porque la lista exacta de columnas está a una consulta INFORMATION_SCHEMA de distancia y siempre es correcta para su versión.

La biblioteca de consultas guardadas es el núcleo confirmado más una superposición de escritura en CW_DB_QUERY_LIBRARY (JSON, { version, queries[] }). Las entradas de la superposición ganan por slug, cw_db_save_query añade a ella, y scripts/import-queries.mjs la rellena desde una exportación existente de BrightGauge:

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

Las consultas importadas permanecen fuera de este repositorio: son sus informes y pueden contener nombres de empresa y tarifas. En un contenedor, apunte CW_DB_QUERY_LIBRARY a un almacenamiento montado o las consultas guardadas morirán con el contenedor.

El inicio de sesión es el límite de seguridad

No hay validación de sentencias: el servidor envía el SQL del modelo a SQL Server tal cual, por lo que lo que el inicio de sesión pueda hacer es exactamente lo que puede ocurrir. Dos scripts lo configuran y lo demuestran.

Créelo — edite las cuatro variables de la parte superior, ejecútelo como administrador del sistema. @WhatIf tiene el valor predeterminado 1, por lo que la primera ejecución solo imprime el plan:

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

Crea el inicio de sesión sin ningún rol de servidor, lo añade a db_datareader en una base de datos, deniega todo lo demás (EXECUTE, todas las escrituras, DDL, BACKUP) y deniega SELECT en cada columna de aspecto de credencial que descubra: los nombres cambian entre versiones de Manage y cada MSP añade los suyos, por lo que se encuentran en lugar de estar codificados. Volver a ejecutarlo es seguro y así es como se vuelven a aplicar las denegaciones después de que una actualización añada tablas. Informa de los ajustes de toda la instancia que deben estar desactivados pero nunca los cambia: deshabilitar xp_cmdshell puede romper otras aplicaciones, por lo que eso sigue siendo una decisión.

Verifíquelo — como el nuevo inicio de sesión, no como administrador:

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

Cada comprobación imprime PASS o FAIL: SELECT funciona, UPDATE/CREATE TABLE se rechazan (dentro de una transacción que siempre revierte, por si falta un DENY), xp_cmdshell/sp_OACreate/OPENROWSET(BULK …) son inalcanzables, una columna de credenciales es ilegible y el inicio de sesión no tiene ningún rol elevado. Un FAIL significa que aún no se debe habilitar el conjunto de herramientas.

Dos consecuencias que conviene saber de antemano:

  • SELECT * falla en cualquier tabla con una columna denegada, en lugar de devolver las demás columnas. Ese es el objetivo; el error de la herramienta le dice al modelo que nombre sus columnas.

  • EXECUTE es el permiso que importa. Con él, el "SQL de solo lectura" se convierte en ejecución remota de código como la cuenta de servicio de SQL Server: xp_cmdshell, sp_OACreate, sp_send_dbmail, xp_dirtree para captura NTLM. OPENROWSET/BULK INSERT leen archivos sin necesidad de EXECUTE, por lo que las consultas distribuidas ad hoc también deben estar desactivadas.

Operativamente: prefiere una secundaria de AG legible o una copia de informes restaurada en lugar de la principal de producción, protege con cortafuegos el puerto SQL hacia el host MCP y mantén una sesión de SQL Audit o Extended Events en este inicio de sesión.

Referencia de configuración

Variable

Default

Propósito

CW_SITE

—

Host de ConnectWise (en la nube o local; se aceptan URL completas)

CW_COMPANY_ID

—

Identificador de la empresa de inicio de sesión

CW_CLIENT_ID

—

clientId de integración

CW_PUBLIC_KEY / CW_PRIVATE_KEY

—

Claves de miembro de la API: necesarias para stdio; sin usar en HTTP (BYOK)

CW_MEMBER_IDENTIFIER

—

Miembro al que pertenecen las claves stdio (my-tickets/my-time)

TRANSPORT / PORT

stdio / 3000

Selección de transporte

CW_TOOLSETS

all

Conjuntos de herramientas habilitados (claves/preajustes); HTTP los sobrescribe por sesión mediante x-cw-toolsets

CW_DB_HOST

—

Host de SQL Server de ConnectWise, o host\INSTANCE: habilita el conjunto de herramientas sql

CW_DB_NAME / CW_DB_USER / CW_DB_PASSWORD

—

Base de datos y su inicio de sesión dedicado de solo lectura (los cuatro son necesarios a la vez)

CW_DB_PORT

1433

Puerto TCP; no es válido junto con una instancia con nombre

CW_DB_ENCRYPT / CW_DB_TRUST_SERVER_CERT

true / true

TLS y aceptación del certificado autofirmado habitual en instalaciones locales

CW_DB_READ_UNCOMMITTED

true

Lectura en READ UNCOMMITTED para que los informes nunca bloqueen a los escritores de producción

CW_DB_QUERY_TIMEOUT_MS / CW_DB_MAX_ROWS

30000 / 200

Límite de tiempo y de filas por consulta

CW_DB_QUERY_LIBRARY

—

Ruta al archivo de consultas guardadas editable; sin definir ⇒ solo consultas integradas, sin herramienta de guardado

Notas y límites

  • Las búsquedas de tickets usan por defecto los tickets abiertos; los nombres de estado/tablero son exactos, los filtros de texto son subcadenas.

  • Las marcas de tiempo deben tener segundos completos: el servidor normaliza (ConnectWise rechaza los segundos fraccionarios).

  • Las entradas de tiempo requieren un período de informe de tiempo abierto en ConnectWise para la fecha de la entrada; si no existe, se transmite el mensaje de la API.

  • /system/myAccount falta en algunas versiones locales: proporciona el identificador de miembro explícitamente (CW_MEMBER_IDENTIFIER o x-cw-member-id) para "my tickets"/"my time".

  • Las notas de discusión son visibles para el cliente; las notas internas no lo son: la herramienta lo hace explícito.

  • cw_db_query se detiene en max_rows (200 por defecto) o en un presupuesto de ~20 000 caracteres y cancela la consulta en el servidor; la respuesta indica qué límite se alcanzó. El plazo por consulta es de 30 s por defecto, 120 s como máximo.

  • La conexión a la base de datos lee en READ UNCOMMITTED para que un escaneo de informes no pueda bloquear a un técnico que guarda un ticket. El coste son lecturas sucias: los recuentos son aproximados bajo escrituras concurrentes. Establece CW_DB_READ_UNCOMMITTED=false si un informe debe ser exacto.

  • SELECT * falla en cualquier tabla con una columna con DENY: nombra las columnas que necesites.

  • Las instancias de ConnectWise alojadas en la nube no tienen acceso a la base de datos; el conjunto de herramientas sql es solo local.

Desarrollo

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

Licencia

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