feat: add finance, procurement and agreement recap tools - #81
Open
asachs01 wants to merge 1 commit into
Open
Conversation
Finance was the largest remaining gap in this server's coverage: an MSP
finance team could read agreements and invoices, but nothing about the
buy side, the sell side, or agreement burn-down. Adds 10 read-only tools.
Procurement (src/tools/finance-procurement.ts):
cw_search_purchase_orders GET /procurement/purchaseorders
cw_get_purchase_order GET /procurement/purchaseorders/{id}
cw_get_purchase_order_items GET /procurement/purchaseorders/{id}/lineitems
cw_search_procurement_products GET /procurement/products
cw_get_procurement_product GET /procurement/products/{id}
Sales orders (src/tools/finance-procurement.ts):
cw_search_sales_orders GET /sales/orders
cw_get_sales_order GET /sales/orders/{id}
cw_get_sales_order_products GET /procurement/products, scoped to the order
Agreement recaps (src/tools/agreements.ts):
cw_search_agreement_recaps GET /finance/agreementrecap/
cw_get_agreement_recap GET /finance/agreementrecap/{id}
Procurement product *items* are catalog SKUs instantiated onto a ticket,
project, order or opportunity, carrying their own price, cost and margin.
They are not the catalog SKU definitions, which stay under
cw_search_catalog_items; both descriptions point at each other so the
calling model picks the right one.
cw_get_sales_order_products is always scoped to its order. Caller-supplied
conditions are ANDed with that scope rather than replacing it, so the tool
cannot be talked out of its own filter. There is a test for that.
Every path was verified against ConnectWise's published OpenAPI contract
("Connectwise Manage Public Endpoints", 2025.16) rather than trusted from
the forks. Two findings are pinned by tests and comments because they look
like typos and are not: /finance/agreementrecap/ is documented only WITH a
trailing slash while its by-id sibling has none, and ProductItem carries a
nested salesOrder reference with no flat salesOrderId companion, so the
sales-order filter is salesOrder/id=N.
Tests drive the Worker entrypoint over real MCP JSON-RPC with fetch stubbed
and assert the ConnectWise URL each tool actually builds -- a tool can be
registered, typecheck, and still call the wrong path.
Attribution (Apache-2.0, as is this project):
The procurement, purchase-order and sales-order tools are derived from
work by @Tekscape-finance in Tekscape-finance/connectwise-manage-mcp.
The agreement-recap tools are derived from work by @Cloudwize-Technologies
in Cloudwize-Technologies/connectwise-manage-mcp.
Thank you to both.
|
Warning Review limit reachedNext included review available in 47 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (6)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds 10 read-only finance and procurement tools. Finance was the largest remaining gap in this server's coverage: an MSP finance team could read agreements and invoices, but nothing about the buy side, the sell side, or agreement burn-down.
Procurement —
src/tools/finance-procurement.tscw_search_purchase_ordersGET /procurement/purchaseorderscw_get_purchase_orderGET /procurement/purchaseorders/{id}cw_get_purchase_order_itemsGET /procurement/purchaseorders/{id}/lineitemscw_search_procurement_productsGET /procurement/productscw_get_procurement_productGET /procurement/products/{id}Sales orders —
src/tools/finance-procurement.tscw_search_sales_ordersGET /sales/orderscw_get_sales_orderGET /sales/orders/{id}cw_get_sales_order_productsGET /procurement/products, scoped to the orderAgreement recaps —
src/tools/agreements.tscw_search_agreement_recapsGET /finance/agreementrecap/cw_get_agreement_recapGET /finance/agreementrecap/{id}The recap is the billing rollup ConnectWise computes per agreement — starting, used, remaining, available and overrun amounts, unbilled periods, last and next invoice. It answers burn-down and overage questions without summing additions by hand.
Notes
Procurement product items are catalog SKUs instantiated onto a ticket, project, order or opportunity, carrying their own price, cost and margin. They are not the catalog SKU definitions, which stay under
cw_search_catalog_items. Both tool descriptions point at each other so the calling model picks the right one.cw_get_sales_order_productsis always scoped to its order. Caller-suppliedconditionsare ANDed with that scope rather than replacing it, so the tool cannot be talked out of its own filter — there's a test for exactly that.Every tool is read-only. No write paths were added.
Verification against the vendor contract
Paths were checked against ConnectWise's published OpenAPI contract (
Connectwise Manage Public Endpoints, 2025.16, openapi 3.0.1) rather than trusted from the upstream forks. Two findings are pinned by tests and code comments because they look like typos and are not:/finance/agreementrecap/is documented only with a trailing slash. The slash-less form appears nowhere in the contract, and the by-id sibling/finance/agreementrecap/{id}has no slash. Its neighbour/finance/agreementsalso has no slash. Corroborated by three independently generated clients (Ruby, Go, TypeScript) that all emit the trailing slash. Don't "tidy" it.ProductItemhas a nestedsalesOrderreference and no flatsalesOrderId. So the sales-order filter issalesOrder/id=N. CW does ship flat*Idcompanions elsewhere on that same model (warehouseId,locationId, …), so the absence here is meaningful.salesOrderId=Nwould have been the silently-failing form.Also confirmed:
lineitemsis all-lowercase with no trailing slash on the purchase-order path (lineItemsappears nowhere in the contract), and — noted in a comment for whoever adds it next —/sales/orders/{id}/lineitems/does carry a trailing slash. CW is not symmetric here.src/__tests__/finance-procurement.test.tsdrives the Worker entrypoint over real MCP JSON-RPC withfetchstubbed, and asserts the ConnectWise URL each tool actually builds. A tool can be registered, typecheck, and still call the wrong path; this is the thing worth pinning.Test run
Attribution
Derived from two community forks, both Apache-2.0, as is this project:
Tekscape-finance/connectwise-manage-mcp— a finance team at an MSP who built what they needed.Cloudwize-Technologies/connectwise-manage-mcp.Thank you to both.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.