{
  "markdown": "# connectwise-cpq-mcp\n\nMCP server for [ConnectWise CPQ (Sell)](https://developer.connectwise.com/Products/ConnectWise_CPQ) —\nquotes, line items, customers, terms, tabs, templates, tax codes, recurring revenues, and users.\n\nBuilt on the MCP **2026-07-28** spec via the split v2 SDK\n(`@modelcontextprotocol/server` / `/node` / `/client` `^2.0.0-beta.5`) with **dual-era\nserving**: one shared `McpServerFactory` behind `createMcpHandler({ legacy: 'stateless' })`\nanswers both 2025-era `initialize`-handshake clients (the WYRE gateway today) and modern\n2026-07-28 envelope clients — with an identical, deterministic 25-tool surface for every\ncaller. Ships as a GHCR container only (no MCPB bundle).\n\n## Tools (25, flat)\n\nReads: `cpq_test_connection`, `cpq_search_quotes`, `cpq_get_quote`, `cpq_get_quote_versions`,\n`cpq_search_quote_items`, `cpq_get_quote_item`, `cpq_list_quote_customers`,\n`cpq_search_quote_tabs`, `cpq_list_quote_terms`, `cpq_list_templates`, `cpq_list_tax_codes`,\n`cpq_list_recurring_revenues`, `cpq_list_users`.\n\nWrites: `cpq_create_quote_from_template`, `cpq_update_quote` (⚠ HIGH-IMPACT),\n`cpq_create_quote_item`, `cpq_update_quote_item`, `cpq_update_quote_customer`,\n`cpq_create_quote_term`, `cpq_update_quote_term`, and the ⚠ DESTRUCTIVE — IRREVERSIBLE\ndeletes: `cpq_delete_quote_item`, `cpq_delete_quote_term`, `cpq_delete_quote_customer`,\n`cpq_delete_quote_version`, `cpq_delete_quote`.\n\nQuote creation is copy-only (`/api/quotes/copyById`) — the CPQ API has no create-from-scratch,\npublish/e-sign, order-porting, PDF, or product-catalog endpoints (pair with connectwise-psa\nfor those).\n\n## Credentials\n\nCPQ requires an **API user** and CPQ 2022.2+. Three parts, all required:\n\n| Env var (env mode) | Gateway header (`AUTH_MODE=gateway`) | Where to find it |\n|---|---|---|\n| `CPQ_ACCESS_KEY` | `X-CPQ-Access-Key` | Sell URL: `...home?accesskey=<this>` |\n| `CPQ_PUBLIC_KEY` | `X-CPQ-Public-Key` | Settings → Organization Settings → API Keys |\n| `CPQ_PRIVATE_KEY` | `X-CPQ-Private-Key` | Shown once at key creation |\n\nIn gateway mode a request missing any header is answered `401` (JSON-RPC error `-32001`)\nbefore the MCP handler runs — it never falls through to env credentials.\n\n## Running\n\n```bash\nexport NODE_AUTH_TOKEN=$(gh auth token)   # GitHub Packages auth for @wyre-ai/*\nnpm install\nnpm run build\nnode dist/index.js                        # stdio (default)\nMCP_TRANSPORT=http node dist/index.js     # HTTP on :8080 (/mcp, /health)\nnode scripts/smoke-dual-era.mjs           # proves both protocol eras serve the same tools\n```\n\n> **Local-dev note:** `@wyre-technology/node-connectwise-cpq` is declared at `^1.0.0` but is\n> not yet published; until the SDK's first release lands, `npm ci` from a fresh clone fails.\n> Install the locally built SDK tarball instead:\n> `npm install /path/to/wyre-ai-node-connectwise-cpq-0.0.0-semantically-released.tgz`\n> (then keep `package.json` at `^1.0.0`).\n\nDocker (linux/amd64 per fleet law):\n\n```bash\ndocker build --platform linux/amd64 --build-arg GITHUB_TOKEN=$(gh auth token) \\\n  -t connectwise-cpq-mcp .\ndocker run -p 8080:8080 -e CPQ_ACCESS_KEY=... -e CPQ_PUBLIC_KEY=... -e CPQ_PRIVATE_KEY=... \\\n  connectwise-cpq-mcp\n```\n\n## MCP Apps quote card\n\n`cpq_get_quote` advertises a read-only MCP Apps card\n(`ui://connectwise-cpq/quote-card.html`) showing the quote header, status badges, a\nline-item summary, and totals. The card is purely additive: hosts without MCP Apps support\nget the full QuoteView JSON (the `_card` field is extra, never a replacement), and any card\nbuild failure leaves the JSON untouched. Rebuild the embedded UI with `npm run build:ui`\n(output committed at `src/generated/quote-card-html.ts`). Brand at serve time via\n`MCP_BRAND_*` env vars.\n\n## Elicitation and destructive-action consent\n\nWhere the connected client supports elicitation, the server asks before acting: date range\non unfiltered quote searches, template pick on ambiguous names, tab pick when adding items,\nand confirmation before every delete. Elicitation rides the SDK v2 MRTR seam: handlers\nreturn `input_required` results (embedded `elicitation/create` requests) that 2026-07-28\nclients fulfil and retry, and that the SDK's legacy shim fulfils server-side for 2025-era\nstateful connections (stdio). All elicitation is MRTR-safe: no vendor mutation ever fires\nbefore an elicitation point, so a client retry of the original request cannot duplicate a\nwrite.\n\nCallers that never declared the form-elicitation capability — including stateless legacy\nHTTP requests, which is how the WYRE Conduit gateway connects — cannot be prompted at all.\nWhat that means depends on the stakes:\n\n- **Optional** elicitation degrades gracefully (design.md §4): an unfiltered search falls\n  back to a default 90-day range and says so, and the ambiguous template/tab pickers\n  return an error listing the candidates.\n- **Destructive** tools fail closed. A client that cannot answer has not consented, so the\n  five `cpq_delete_*` tools refuse to run and return an actionable error naming what to do.\n  A non-interactive caller opts in per call with `\"confirm_destructive_action\": true`,\n  declared in each destructive tool's input schema so the gate is actually satisfiable.\n  That argument is consulted *only* when no prompt is possible — it can never skip a\n  confirmation an interactive user would otherwise have seen.\n\n## Vendor quirks encoded here\n\n- Missing `Authorization` header → CPQ answers **500** (not 401); credentials are validated\n  client-side before any request.\n- The real 401 body carries a vendor typo (`\"...has occured during basic auth validation\"`).\n- `Content-Type: application/json; version=1.0` on every request (media-type versioning).\n- List responses are bare JSON arrays — pagination terminates on a short page.\n- Condition dates must be date-only and bracketed: `createDate >= [2026-07-01]`.\n- PATCH bodies are RFC 6902 JSON Patch arrays.\n\n## License\n\nApache-2.0 © WYRE Technology\n",
  "bytes": 5950,
  "sha": "27392e6e1b11b0ff2731632ae3ba65c3e38d48b0776ad053b69aa80f963108b4",
  "repo_slug": "wyre-technology/connectwise-cpq-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_wyre_technology_connectwise_cp_c69a6a23/readme"
}