@procurementexpress.com/mcp 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/bump-version/SKILL.md +77 -0
- package/.claude/skills/commit/SKILL.md +73 -0
- package/.claude/skills/npm-publish/SKILL.md +65 -0
- package/.claude/skills/pex-approval-flows/SKILL.md +122 -0
- package/.claude/skills/pex-approval-flows/references/conditions.md +90 -0
- package/.claude/skills/pex-auth/SKILL.md +80 -0
- package/.claude/skills/pex-budgets/SKILL.md +73 -0
- package/.claude/skills/pex-companies/SKILL.md +113 -0
- package/.claude/skills/pex-departments/SKILL.md +61 -0
- package/.claude/skills/pex-invoices/SKILL.md +125 -0
- package/.claude/skills/pex-invoices/references/line-items.md +55 -0
- package/.claude/skills/pex-payments/SKILL.md +79 -0
- package/.claude/skills/pex-purchase-orders/SKILL.md +167 -0
- package/.claude/skills/pex-purchase-orders/references/line-items.md +53 -0
- package/.claude/skills/pex-purchase-orders/references/workflows.md +74 -0
- package/.claude/skills/pex-settings/SKILL.md +128 -0
- package/.claude/skills/pex-suppliers/SKILL.md +113 -0
- package/README.md +118 -25
- package/dist/api-client.d.ts +1 -0
- package/dist/api-client.js +3 -0
- package/dist/tools/approval-flows.js +130 -25
- package/dist/tools/budgets.js +30 -20
- package/dist/tools/comments.js +4 -4
- package/dist/tools/companies.js +57 -7
- package/dist/tools/departments.js +6 -6
- package/dist/tools/invoices.js +100 -31
- package/dist/tools/payments.js +45 -13
- package/dist/tools/products.js +10 -5
- package/dist/tools/purchase-orders.js +178 -35
- package/dist/tools/supplementary.js +57 -14
- package/dist/tools/suppliers.js +38 -19
- package/dist/tools/tax-rates.js +15 -9
- package/dist/tools/users.js +8 -5
- package/dist/tools/webhooks.js +59 -9
- package/package.json +5 -4
package/dist/tools/invoices.js
CHANGED
|
@@ -1,46 +1,88 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
|
+
const customFieldValueSchema = z.object({
|
|
4
|
+
id: z.number().int().optional().describe("Custom field value ID (for updates)"),
|
|
5
|
+
value: z.string().describe("Custom field value"),
|
|
6
|
+
custom_field_id: z.number().int().describe("Custom field ID"),
|
|
7
|
+
});
|
|
3
8
|
const invoiceLineItemSchema = z.object({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
id: z.number().int().optional().describe("Line item ID (for updates)"),
|
|
10
|
+
description: z.string().optional().describe("Line item description"),
|
|
11
|
+
unit_price: z.number().optional().describe("Unit price"),
|
|
12
|
+
quantity: z.number().optional().describe("Quantity"),
|
|
13
|
+
vat: z.number().optional().describe("VAT/tax percentage"),
|
|
8
14
|
net_amount: z.number().optional().describe("Net amount"),
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
sequence_no: z.number().int().optional().describe("Sequence number for ordering"),
|
|
16
|
+
tax_rate_id: z.number().int().optional().describe("Tax rate ID"),
|
|
17
|
+
chart_of_account_id: z.number().int().optional().describe("Chart of account ID (GL code)"),
|
|
18
|
+
qbo_customer_id: z.number().int().optional().describe("QuickBooks customer ID"),
|
|
19
|
+
quickbooks_class_id: z.number().int().optional().describe("QuickBooks class ID"),
|
|
20
|
+
qbo_line_description: z.string().optional().describe("QuickBooks line description override"),
|
|
21
|
+
purchase_order_id: z.number().int().optional().describe("Related purchase order ID"),
|
|
22
|
+
purchase_order_item_id: z.number().int().optional().describe("Related PO line item ID"),
|
|
23
|
+
billable_status: z.string().optional().describe("Billable status for QuickBooks"),
|
|
24
|
+
_destroy: z.boolean().optional().describe("Set true to remove this line item on update"),
|
|
25
|
+
custom_field_values_attributes: z.array(customFieldValueSchema).optional().describe("Custom field values for this line item"),
|
|
11
26
|
});
|
|
12
27
|
export function registerInvoiceTools(server, apiClient) {
|
|
13
28
|
server.registerTool("list_invoices", {
|
|
14
|
-
description: "List invoices with pagination and filters (
|
|
29
|
+
description: "List invoices with pagination and filters. Returns paginated results with meta info (current_page, next_page, prev_page, total_pages, total_count). Per-page count is controlled by company settings (default 10, allowed: 10, 20, 50, 100).",
|
|
15
30
|
inputSchema: {
|
|
16
|
-
page: z.number().int().positive().optional().describe("Page number"),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
page: z.number().int().positive().optional().describe("Page number (default: 1)"),
|
|
32
|
+
per_page: z.number().int().optional().describe("Results per page (allowed: 10, 20, 50, 100)"),
|
|
33
|
+
search: z.string().optional().describe("Search term — matches invoice number, supplier name"),
|
|
34
|
+
invoice_statuses_filter: z
|
|
35
|
+
.enum(["awaiting_review", "outstanding", "ready_to_pay", "settled", "cancelled"])
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Filter by invoice status"),
|
|
38
|
+
archived: z.boolean().optional().describe("Filter by archived status (default: false)"),
|
|
20
39
|
supplier_id: z.number().int().optional().describe("Filter by supplier ID"),
|
|
21
|
-
|
|
40
|
+
requester_id: z.number().int().optional().describe("Filter by requester/creator user ID"),
|
|
41
|
+
approver_id: z.number().int().optional().describe("Filter by approver user ID"),
|
|
42
|
+
department_id: z.number().int().optional().describe("Filter by department ID (via linked POs)"),
|
|
43
|
+
invoice_date_filter: z
|
|
44
|
+
.enum(["last 7days", "last 30days", "last 60days", "last 90days", "last 180days", "last 1year", "current_month", "current_year", "last_month", "last_year"])
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Predefined date range filter"),
|
|
47
|
+
sage_exported: z.boolean().optional().describe("Filter by Sage export status"),
|
|
48
|
+
sort: z.string().optional().describe("Sort column (e.g. 'invoices.created_at', 'invoices.issue_date')"),
|
|
49
|
+
direction: z.enum(["asc", "desc"]).optional().describe("Sort direction (default: desc)"),
|
|
22
50
|
},
|
|
23
51
|
}, withErrorHandling(async (args) => {
|
|
24
52
|
const params = new URLSearchParams();
|
|
25
53
|
if (args.page)
|
|
26
54
|
params.set("page", String(args.page));
|
|
55
|
+
if (args.per_page)
|
|
56
|
+
params.set("per_page", String(args.per_page));
|
|
57
|
+
if (args.search)
|
|
58
|
+
params.set("search[query]", args.search);
|
|
59
|
+
if (args.invoice_statuses_filter)
|
|
60
|
+
params.set("invoice_statuses_filter", args.invoice_statuses_filter);
|
|
27
61
|
if (args.archived !== undefined)
|
|
28
62
|
params.set("archived", String(args.archived));
|
|
63
|
+
if (args.supplier_id)
|
|
64
|
+
params.set("supplier_id", String(args.supplier_id));
|
|
29
65
|
if (args.requester_id)
|
|
30
66
|
params.set("requester_id", String(args.requester_id));
|
|
31
67
|
if (args.approver_id)
|
|
32
68
|
params.set("approver_id", String(args.approver_id));
|
|
33
|
-
if (args.
|
|
34
|
-
params.set("
|
|
69
|
+
if (args.department_id)
|
|
70
|
+
params.set("department_id", String(args.department_id));
|
|
35
71
|
if (args.invoice_date_filter)
|
|
36
72
|
params.set("invoice_date_filter", args.invoice_date_filter);
|
|
73
|
+
if (args.sage_exported !== undefined)
|
|
74
|
+
params.set("sage_exported", String(args.sage_exported));
|
|
75
|
+
if (args.sort)
|
|
76
|
+
params.set("sort", args.sort);
|
|
77
|
+
if (args.direction)
|
|
78
|
+
params.set("direction", args.direction);
|
|
37
79
|
const query = params.toString();
|
|
38
80
|
const path = `${apiClient.buildPath("/invoices")}${query ? `?${query}` : ""}`;
|
|
39
81
|
const result = await apiClient.get(path);
|
|
40
82
|
return jsonResponse(result);
|
|
41
83
|
}));
|
|
42
84
|
server.registerTool("get_invoice", {
|
|
43
|
-
description: "Get invoice details by ID",
|
|
85
|
+
description: "Get invoice details by ID, including line items, linked POs, and comments",
|
|
44
86
|
inputSchema: {
|
|
45
87
|
id: z.number().int().positive().describe("Invoice ID"),
|
|
46
88
|
},
|
|
@@ -49,24 +91,29 @@ export function registerInvoiceTools(server, apiClient) {
|
|
|
49
91
|
return jsonResponse(invoice);
|
|
50
92
|
}));
|
|
51
93
|
server.registerTool("create_invoice", {
|
|
52
|
-
description: "Create a new invoice",
|
|
94
|
+
description: "Create a new invoice. If the company has 'create invoice in awaiting review' enabled, the invoice starts in awaiting_review status.",
|
|
53
95
|
inputSchema: {
|
|
54
|
-
invoice_number: z.string().optional().describe("Invoice number"),
|
|
55
|
-
issue_date: z.string().optional().describe("Issue date"),
|
|
56
|
-
|
|
96
|
+
invoice_number: z.string().optional().describe("Invoice number/reference"),
|
|
97
|
+
issue_date: z.string().optional().describe("Issue date (format depends on company date_format)"),
|
|
98
|
+
uploaded_date: z.string().optional().describe("Upload date"),
|
|
57
99
|
received_date: z.string().optional().describe("Received date"),
|
|
58
100
|
due_date: z.string().optional().describe("Due date"),
|
|
59
|
-
gross_amount: z.number().describe("Gross amount"),
|
|
60
|
-
currency_id: z.number().int().describe("Currency ID"),
|
|
61
|
-
|
|
101
|
+
gross_amount: z.number().optional().describe("Gross amount"),
|
|
102
|
+
currency_id: z.number().int().optional().describe("Currency ID"),
|
|
103
|
+
supplier_id: z.number().int().optional().describe("Supplier ID"),
|
|
104
|
+
standalone_invoice: z.boolean().optional().describe("True if invoice is not linked to any PO"),
|
|
105
|
+
payment_term_id: z.number().int().optional().describe("Payment term ID"),
|
|
106
|
+
selected_purchase_order_ids: z.array(z.number().int()).optional().describe("PO IDs to link this invoice to"),
|
|
62
107
|
line_items: z.array(invoiceLineItemSchema).optional().describe("Invoice line items"),
|
|
108
|
+
custom_field_values_attributes: z.array(customFieldValueSchema).optional().describe("Invoice-level custom field values"),
|
|
63
109
|
},
|
|
64
110
|
}, withErrorHandling(async (args) => {
|
|
65
|
-
const { line_items, ...invoiceData } = args;
|
|
111
|
+
const { line_items, custom_field_values_attributes, ...invoiceData } = args;
|
|
66
112
|
const body = {
|
|
67
113
|
invoice: {
|
|
68
114
|
...invoiceData,
|
|
69
115
|
...(line_items ? { invoice_line_items_attributes: line_items } : {}),
|
|
116
|
+
...(custom_field_values_attributes ? { custom_field_values_attributes } : {}),
|
|
70
117
|
},
|
|
71
118
|
};
|
|
72
119
|
const invoice = await apiClient.post(apiClient.buildPath("/invoices"), body);
|
|
@@ -78,45 +125,60 @@ export function registerInvoiceTools(server, apiClient) {
|
|
|
78
125
|
id: z.number().int().positive().describe("Invoice ID"),
|
|
79
126
|
invoice_number: z.string().optional().describe("Invoice number"),
|
|
80
127
|
issue_date: z.string().optional().describe("Issue date"),
|
|
81
|
-
|
|
128
|
+
uploaded_date: z.string().optional().describe("Upload date"),
|
|
129
|
+
received_date: z.string().optional().describe("Received date"),
|
|
82
130
|
due_date: z.string().optional().describe("Due date"),
|
|
83
131
|
gross_amount: z.number().optional().describe("Gross amount"),
|
|
132
|
+
currency_id: z.number().int().optional().describe("Currency ID"),
|
|
133
|
+
supplier_id: z.number().int().optional().describe("Supplier ID"),
|
|
134
|
+
standalone_invoice: z.boolean().optional().describe("Standalone invoice flag"),
|
|
135
|
+
payment_term_id: z.number().int().optional().describe("Payment term ID"),
|
|
136
|
+
selected_purchase_order_ids: z.array(z.number().int()).optional().describe("PO IDs to link"),
|
|
137
|
+
line_items: z.array(invoiceLineItemSchema).optional().describe("Invoice line items (include id to update, _destroy to remove)"),
|
|
138
|
+
custom_field_values_attributes: z.array(customFieldValueSchema).optional().describe("Invoice-level custom field values"),
|
|
84
139
|
},
|
|
85
140
|
}, withErrorHandling(async (args) => {
|
|
86
|
-
const { id, ...data } = args;
|
|
87
|
-
const
|
|
141
|
+
const { id, line_items, custom_field_values_attributes, ...data } = args;
|
|
142
|
+
const body = {
|
|
143
|
+
invoice: {
|
|
144
|
+
...data,
|
|
145
|
+
...(line_items ? { invoice_line_items_attributes: line_items } : {}),
|
|
146
|
+
...(custom_field_values_attributes ? { custom_field_values_attributes } : {}),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const invoice = await apiClient.put(apiClient.buildPath(`/invoices/${id}`), body);
|
|
88
150
|
return jsonResponse(invoice);
|
|
89
151
|
}));
|
|
90
152
|
server.registerTool("accept_invoice", {
|
|
91
|
-
description: "Accept an invoice that is
|
|
153
|
+
description: "Accept an invoice that is in awaiting_review status",
|
|
92
154
|
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
93
155
|
}, withErrorHandling(async (args) => {
|
|
94
156
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/accept`));
|
|
95
157
|
return jsonResponse(result);
|
|
96
158
|
}));
|
|
97
159
|
server.registerTool("approve_invoice", {
|
|
98
|
-
description: "Approve an invoice",
|
|
160
|
+
description: "Approve an invoice (requires invoice approval permission)",
|
|
99
161
|
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
100
162
|
}, withErrorHandling(async (args) => {
|
|
101
163
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/approve`));
|
|
102
164
|
return jsonResponse(result);
|
|
103
165
|
}));
|
|
104
166
|
server.registerTool("reject_invoice", {
|
|
105
|
-
description: "Reject an invoice",
|
|
167
|
+
description: "Reject an invoice (requires invoice approval permission)",
|
|
106
168
|
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
107
169
|
}, withErrorHandling(async (args) => {
|
|
108
170
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/reject`));
|
|
109
171
|
return jsonResponse(result);
|
|
110
172
|
}));
|
|
111
173
|
server.registerTool("cancel_invoice", {
|
|
112
|
-
description: "Cancel an invoice",
|
|
174
|
+
description: "Cancel an invoice (requires cancel permission)",
|
|
113
175
|
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
114
176
|
}, withErrorHandling(async (args) => {
|
|
115
177
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/cancel`));
|
|
116
178
|
return jsonResponse(result);
|
|
117
179
|
}));
|
|
118
180
|
server.registerTool("archive_invoice", {
|
|
119
|
-
description: "Archive an invoice",
|
|
181
|
+
description: "Archive an invoice (requires archive permission)",
|
|
120
182
|
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
121
183
|
}, withErrorHandling(async (args) => {
|
|
122
184
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/archive`));
|
|
@@ -129,4 +191,11 @@ export function registerInvoiceTools(server, apiClient) {
|
|
|
129
191
|
const result = await apiClient.put(apiClient.buildPath(`/invoices/${args.id}/dearchive`));
|
|
130
192
|
return jsonResponse(result);
|
|
131
193
|
}));
|
|
194
|
+
server.registerTool("rerun_invoice_approval_flow", {
|
|
195
|
+
description: "Rerun the approval flow for an invoice. Useful when approval flow rules have changed.",
|
|
196
|
+
inputSchema: { id: z.number().int().positive().describe("Invoice ID") },
|
|
197
|
+
}, withErrorHandling(async (args) => {
|
|
198
|
+
const result = await apiClient.post(apiClient.buildPath(`/invoices/${args.id}/rerun_approval_flow`));
|
|
199
|
+
return jsonResponse(result);
|
|
200
|
+
}));
|
|
132
201
|
}
|
package/dist/tools/payments.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
3
|
export function registerPaymentTools(server, apiClient) {
|
|
4
|
+
server.registerTool("get_payment", {
|
|
5
|
+
description: "Get payment details by ID",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
id: z.number().int().positive().describe("Payment ID"),
|
|
8
|
+
},
|
|
9
|
+
}, withErrorHandling(async (args) => {
|
|
10
|
+
const payment = await apiClient.get(apiClient.buildPath(`/npayments/${args.id}`));
|
|
11
|
+
return jsonResponse(payment);
|
|
12
|
+
}));
|
|
4
13
|
server.registerTool("create_payment", {
|
|
5
|
-
description: "Create a payment (feature flagged).
|
|
14
|
+
description: "Create a payment to settle invoices and/or purchase orders (feature flagged — contact sales to enable). The payment date must match the company's date_format setting.",
|
|
6
15
|
inputSchema: {
|
|
7
|
-
|
|
8
|
-
reference: z.string().optional().describe("Reference number"),
|
|
16
|
+
reference: z.string().optional().describe("Payment reference number"),
|
|
9
17
|
supplier_id: z.number().int().describe("Supplier ID"),
|
|
10
18
|
ptype: z
|
|
11
19
|
.enum([
|
|
@@ -19,44 +27,68 @@ export function registerPaymentTools(server, apiClient) {
|
|
|
19
27
|
"other",
|
|
20
28
|
])
|
|
21
29
|
.describe("Payment type"),
|
|
22
|
-
|
|
30
|
+
payment_mode: z.string().optional().describe("Payment mode"),
|
|
31
|
+
status: z.string().optional().describe("Payment status"),
|
|
32
|
+
date: z.string().describe("Payment date (must match company date_format setting)"),
|
|
23
33
|
currency_id: z.number().int().describe("Currency ID"),
|
|
24
|
-
amount: z.number().describe("Total amount
|
|
34
|
+
amount: z.number().describe("Total payment amount"),
|
|
25
35
|
invoices: z
|
|
26
36
|
.array(z.object({
|
|
27
37
|
invoice_id: z.number().int().describe("Invoice ID"),
|
|
28
|
-
gross_amount: z.number().describe("Amount
|
|
38
|
+
gross_amount: z.number().describe("Amount to apply to this invoice"),
|
|
39
|
+
}))
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Invoices to pay with amounts"),
|
|
42
|
+
purchase_orders: z
|
|
43
|
+
.array(z.object({
|
|
44
|
+
purchase_order_id: z.number().int().describe("Purchase Order ID"),
|
|
45
|
+
budget_id: z.number().int().optional().describe("Budget ID"),
|
|
46
|
+
gross_amount: z.number().describe("Amount to apply to this PO"),
|
|
47
|
+
}))
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Purchase orders to pay with amounts"),
|
|
50
|
+
comments: z
|
|
51
|
+
.array(z.object({
|
|
52
|
+
comment: z.string().describe("Comment text"),
|
|
29
53
|
}))
|
|
30
|
-
.
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Payment comments"),
|
|
31
56
|
},
|
|
32
57
|
}, withErrorHandling(async (args) => {
|
|
33
|
-
const { invoices, ...paymentData } = args;
|
|
58
|
+
const { invoices, purchase_orders, comments, ...paymentData } = args;
|
|
34
59
|
const body = {
|
|
35
60
|
npayment: {
|
|
36
61
|
...paymentData,
|
|
37
|
-
npayment_invoices_attributes: invoices,
|
|
62
|
+
...(invoices ? { npayment_invoices_attributes: invoices } : {}),
|
|
63
|
+
...(purchase_orders ? { npayment_link_orders_attributes: purchase_orders } : {}),
|
|
64
|
+
...(comments ? { npayment_comments_attributes: comments } : {}),
|
|
38
65
|
},
|
|
39
66
|
};
|
|
40
67
|
const payment = await apiClient.post(apiClient.buildPath("/npayments"), body);
|
|
41
68
|
return jsonResponse(payment);
|
|
42
69
|
}));
|
|
43
70
|
server.registerTool("create_po_payment", {
|
|
44
|
-
description: "Create a payment for a purchase order",
|
|
71
|
+
description: "Create a payment for a specific purchase order with optional item-level breakdown. Marks PO items as paid.",
|
|
45
72
|
inputSchema: {
|
|
46
73
|
purchase_order_id: z.number().int().positive().describe("Purchase Order ID"),
|
|
74
|
+
amount: z.number().optional().describe("Total payment amount (if not using item-level payments)"),
|
|
47
75
|
note: z.string().optional().describe("Payment note"),
|
|
48
76
|
item_payments: z
|
|
49
77
|
.array(z.object({
|
|
50
|
-
purchase_order_item_id: z.number().int().describe("PO item ID"),
|
|
78
|
+
purchase_order_item_id: z.number().int().describe("PO line item ID"),
|
|
51
79
|
amount: z.number().describe("Payment amount for this item"),
|
|
52
80
|
}))
|
|
81
|
+
.optional()
|
|
53
82
|
.describe("Item-level payment amounts"),
|
|
54
83
|
},
|
|
55
84
|
}, withErrorHandling(async (args) => {
|
|
56
85
|
const body = {
|
|
57
86
|
payment: {
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
...(args.amount !== undefined ? { amount: args.amount } : {}),
|
|
88
|
+
...(args.note ? { note: args.note } : {}),
|
|
89
|
+
...(args.item_payments
|
|
90
|
+
? { purchase_order_item_payments_attributes: args.item_payments }
|
|
91
|
+
: {}),
|
|
60
92
|
},
|
|
61
93
|
};
|
|
62
94
|
const result = await apiClient.post(apiClient.buildPath(`/purchase_orders/${args.purchase_order_id}/payments`), body);
|
package/dist/tools/products.js
CHANGED
|
@@ -2,13 +2,19 @@ import { z } from "zod";
|
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
3
|
export function registerProductTools(server, apiClient) {
|
|
4
4
|
server.registerTool("list_products", {
|
|
5
|
-
description: "List products with
|
|
5
|
+
description: "List products. When page param is provided, returns paginated response with meta. Without page param, returns all products as an array. Can filter by supplier and archived status.",
|
|
6
6
|
inputSchema: {
|
|
7
|
+
page: z.number().int().positive().optional().describe("Page number — enables pagination"),
|
|
8
|
+
per_page: z.number().int().positive().optional().describe("Results per page (default: 20)"),
|
|
7
9
|
supplier_id: z.number().int().optional().describe("Filter by supplier ID"),
|
|
8
|
-
archived: z.boolean().optional().describe("Filter by archived status"),
|
|
10
|
+
archived: z.boolean().optional().describe("Filter by archived status (default: false)"),
|
|
9
11
|
},
|
|
10
12
|
}, withErrorHandling(async (args) => {
|
|
11
13
|
const params = new URLSearchParams();
|
|
14
|
+
if (args.page)
|
|
15
|
+
params.set("page", String(args.page));
|
|
16
|
+
if (args.per_page)
|
|
17
|
+
params.set("per_page", String(args.per_page));
|
|
12
18
|
if (args.supplier_id)
|
|
13
19
|
params.set("supplier_id", String(args.supplier_id));
|
|
14
20
|
if (args.archived !== undefined)
|
|
@@ -28,12 +34,12 @@ export function registerProductTools(server, apiClient) {
|
|
|
28
34
|
return jsonResponse(product);
|
|
29
35
|
}));
|
|
30
36
|
server.registerTool("create_product", {
|
|
31
|
-
description: "Create a new product",
|
|
37
|
+
description: "Create a new product and associate it with a supplier",
|
|
32
38
|
inputSchema: {
|
|
33
39
|
description: z.string().describe("Product description (required)"),
|
|
40
|
+
supplier_id: z.number().int().describe("Supplier ID (required — product is associated with this supplier)"),
|
|
34
41
|
sku: z.string().optional().describe("SKU code"),
|
|
35
42
|
unit_price: z.number().optional().describe("Unit price"),
|
|
36
|
-
supplier_id: z.number().int().optional().describe("Supplier ID"),
|
|
37
43
|
},
|
|
38
44
|
}, withErrorHandling(async (args) => {
|
|
39
45
|
const product = await apiClient.post(apiClient.buildPath("/products"), { product: args });
|
|
@@ -47,7 +53,6 @@ export function registerProductTools(server, apiClient) {
|
|
|
47
53
|
sku: z.string().optional().describe("SKU code"),
|
|
48
54
|
unit_price: z.number().optional().describe("Unit price"),
|
|
49
55
|
supplier_id: z.number().int().optional().describe("Supplier ID"),
|
|
50
|
-
archived: z.boolean().optional().describe("Archive status"),
|
|
51
56
|
},
|
|
52
57
|
}, withErrorHandling(async (args) => {
|
|
53
58
|
const { id, ...data } = args;
|