@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
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
3
|
const approvalConditionSchema = z.object({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
id: z.number().int().optional().describe("Condition ID (for updates)"),
|
|
5
|
+
property: z.string().describe("Condition property: budget, department, supplier, requester, gross_amount, net_amount, or custom_field_<id>"),
|
|
6
|
+
operator: z.enum(["equals", "not_equals", "greater_than", "less_than", "is_any_of", "is_none_of", "exists", "not_exists", "contains", "not_contains"]).describe("Condition operator"),
|
|
7
|
+
value: z.string().describe("Condition value (single ID or comma-separated IDs for contains/not_contains)"),
|
|
8
|
+
custom_field_id: z.number().int().optional().describe("Custom field ID (when property is custom_field_<id>)"),
|
|
9
|
+
_destroy: z.boolean().optional().describe("Set true to remove this condition on update"),
|
|
8
10
|
});
|
|
9
11
|
const approvalStepSchema = z.object({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
id: z.number().int().optional().describe("Step ID (for updates)"),
|
|
13
|
+
step_no: z.number().int().describe("Step number (execution order)"),
|
|
14
|
+
all_should_approve: z.boolean().describe("True = all approvers in step must approve; false = any one approver suffices"),
|
|
15
|
+
approver_user_ids: z.array(z.number().int()).describe("User IDs of approvers for this step"),
|
|
16
|
+
conditions: z.array(approvalConditionSchema).optional().describe("Step-level conditions (all must match for step to activate)"),
|
|
17
|
+
_destroy: z.boolean().optional().describe("Set true to remove this step on update"),
|
|
14
18
|
});
|
|
15
19
|
export function registerApprovalFlowTools(server, apiClient) {
|
|
16
20
|
server.registerTool("list_approval_flows", {
|
|
17
|
-
description: "List approval flows with search and pagination",
|
|
21
|
+
description: "List active approval flows with search and pagination. Returns paginated results with meta. Requires approval flows feature to be enabled.",
|
|
18
22
|
inputSchema: {
|
|
19
|
-
search: z.string().optional().describe("Search
|
|
20
|
-
page: z.number().int().positive().optional().describe("Page number"),
|
|
21
|
-
per_page: z.number().int().positive().optional().describe("Results per page"),
|
|
22
|
-
sort: z.string().optional().describe("Sort
|
|
23
|
-
direction: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
|
23
|
+
search: z.string().optional().describe("Search by flow name (case-insensitive)"),
|
|
24
|
+
page: z.number().int().positive().optional().describe("Page number (default: 1)"),
|
|
25
|
+
per_page: z.number().int().positive().optional().describe("Results per page (allowed: 10, 20, 50, 100)"),
|
|
26
|
+
sort: z.string().optional().describe("Sort column (e.g. 'id', 'name', 'created_at')"),
|
|
27
|
+
direction: z.enum(["asc", "desc"]).optional().describe("Sort direction (default: desc)"),
|
|
24
28
|
},
|
|
25
29
|
}, withErrorHandling(async (args) => {
|
|
26
30
|
const params = new URLSearchParams();
|
|
@@ -49,13 +53,13 @@ export function registerApprovalFlowTools(server, apiClient) {
|
|
|
49
53
|
return jsonResponse(flow);
|
|
50
54
|
}));
|
|
51
55
|
server.registerTool("create_approval_flow", {
|
|
52
|
-
description: "Create an approval flow with steps, approvers, and conditions. document_type: 0=purchase_order, 1=invoice",
|
|
56
|
+
description: "Create an approval flow with steps, approvers, and conditions. document_type: 0=purchase_order, 1=invoice. Flow-level conditions determine which documents match this flow. Step-level conditions determine which steps activate.",
|
|
53
57
|
inputSchema: {
|
|
54
58
|
name: z.string().describe("Flow name"),
|
|
55
59
|
document_type: z.number().int().min(0).max(1).describe("0=purchase_order, 1=invoice"),
|
|
56
|
-
self_approval_allowed: z.boolean().optional().describe("Allow self-
|
|
57
|
-
steps: z.array(approvalStepSchema).describe("Approval steps with approvers"),
|
|
58
|
-
conditions: z.array(approvalConditionSchema).optional().describe("Flow-level conditions"),
|
|
60
|
+
self_approval_allowed: z.boolean().optional().describe("Allow PO creator to self-approve if they are an approver"),
|
|
61
|
+
steps: z.array(approvalStepSchema).describe("Approval steps with approvers (executed in step_no order)"),
|
|
62
|
+
conditions: z.array(approvalConditionSchema).optional().describe("Flow-level conditions (all must match for flow to apply)"),
|
|
59
63
|
},
|
|
60
64
|
}, withErrorHandling(async (args) => {
|
|
61
65
|
const body = {
|
|
@@ -64,6 +68,7 @@ export function registerApprovalFlowTools(server, apiClient) {
|
|
|
64
68
|
document_type: args.document_type,
|
|
65
69
|
self_approval_allowed: args.self_approval_allowed,
|
|
66
70
|
approval_steps_attributes: args.steps.map((step) => ({
|
|
71
|
+
...(step.id ? { id: step.id } : {}),
|
|
67
72
|
step_no: step.step_no,
|
|
68
73
|
all_should_approve: step.all_should_approve,
|
|
69
74
|
approval_step_approvers_attributes: step.approver_user_ids.map((uid) => ({
|
|
@@ -81,30 +86,84 @@ export function registerApprovalFlowTools(server, apiClient) {
|
|
|
81
86
|
const flow = await apiClient.post(apiClient.buildPath("/approval_flows"), body);
|
|
82
87
|
return jsonResponse(flow);
|
|
83
88
|
}));
|
|
89
|
+
server.registerTool("update_approval_flow", {
|
|
90
|
+
description: "Update an existing approval flow. Include step/condition IDs to update existing items, omit ID for new items, use _destroy to remove.",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
id: z.number().int().positive().describe("Approval Flow ID"),
|
|
93
|
+
name: z.string().optional().describe("Flow name"),
|
|
94
|
+
document_type: z.number().int().min(0).max(1).optional().describe("0=purchase_order, 1=invoice"),
|
|
95
|
+
self_approval_allowed: z.boolean().optional().describe("Allow self-approval"),
|
|
96
|
+
steps: z.array(approvalStepSchema).optional().describe("Approval steps"),
|
|
97
|
+
conditions: z.array(approvalConditionSchema).optional().describe("Flow-level conditions"),
|
|
98
|
+
},
|
|
99
|
+
}, withErrorHandling(async (args) => {
|
|
100
|
+
const { id, steps, conditions, ...flowData } = args;
|
|
101
|
+
const body = {
|
|
102
|
+
approval_flow: {
|
|
103
|
+
...flowData,
|
|
104
|
+
...(steps
|
|
105
|
+
? {
|
|
106
|
+
approval_steps_attributes: steps.map((step) => ({
|
|
107
|
+
...(step.id ? { id: step.id } : {}),
|
|
108
|
+
step_no: step.step_no,
|
|
109
|
+
all_should_approve: step.all_should_approve,
|
|
110
|
+
...(step._destroy ? { _destroy: true } : {}),
|
|
111
|
+
approval_step_approvers_attributes: step.approver_user_ids.map((uid) => ({
|
|
112
|
+
user_id: uid,
|
|
113
|
+
})),
|
|
114
|
+
...(step.conditions
|
|
115
|
+
? { approval_conditions_attributes: step.conditions }
|
|
116
|
+
: {}),
|
|
117
|
+
})),
|
|
118
|
+
}
|
|
119
|
+
: {}),
|
|
120
|
+
...(conditions
|
|
121
|
+
? { approval_conditions_attributes: conditions }
|
|
122
|
+
: {}),
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
const flow = await apiClient.put(apiClient.buildPath(`/approval_flows/${id}`), body);
|
|
126
|
+
return jsonResponse(flow);
|
|
127
|
+
}));
|
|
84
128
|
server.registerTool("delete_approval_flow", {
|
|
85
|
-
description: "Delete an approval flow",
|
|
129
|
+
description: "Delete an approval flow permanently",
|
|
86
130
|
inputSchema: { id: z.number().int().positive().describe("Approval Flow ID") },
|
|
87
131
|
}, withErrorHandling(async (args) => {
|
|
88
132
|
const result = await apiClient.delete(apiClient.buildPath(`/approval_flows/${args.id}`));
|
|
89
133
|
return jsonResponse(result);
|
|
90
134
|
}));
|
|
91
135
|
server.registerTool("archive_approval_flow", {
|
|
92
|
-
description: "Archive an approval flow",
|
|
136
|
+
description: "Archive an approval flow (soft delete — can be restored)",
|
|
93
137
|
inputSchema: { id: z.number().int().positive().describe("Approval Flow ID") },
|
|
94
138
|
}, withErrorHandling(async (args) => {
|
|
95
139
|
const result = await apiClient.put(apiClient.buildPath(`/approval_flows/${args.id}/archive`));
|
|
96
140
|
return jsonResponse(result);
|
|
97
141
|
}));
|
|
142
|
+
server.registerTool("publish_approval_flow", {
|
|
143
|
+
description: "Publish an approval flow to make it active",
|
|
144
|
+
inputSchema: { id: z.number().int().positive().describe("Approval Flow ID") },
|
|
145
|
+
}, withErrorHandling(async (args) => {
|
|
146
|
+
const result = await apiClient.patch(apiClient.buildPath(`/approval_flows/${args.id}/publish`));
|
|
147
|
+
return jsonResponse(result);
|
|
148
|
+
}));
|
|
149
|
+
server.registerTool("unpublish_approval_flow", {
|
|
150
|
+
description: "Unpublish an approval flow to deactivate it",
|
|
151
|
+
inputSchema: { id: z.number().int().positive().describe("Approval Flow ID") },
|
|
152
|
+
}, withErrorHandling(async (args) => {
|
|
153
|
+
const result = await apiClient.patch(apiClient.buildPath(`/approval_flows/${args.id}/unpublish`));
|
|
154
|
+
return jsonResponse(result);
|
|
155
|
+
}));
|
|
98
156
|
server.registerTool("list_approval_flow_runs", {
|
|
99
|
-
description: "List runs
|
|
157
|
+
description: "List approval flow runs (entities that went through this flow) with status and date filters",
|
|
100
158
|
inputSchema: {
|
|
101
159
|
id: z.number().int().positive().describe("Approval Flow ID"),
|
|
102
|
-
status: z.enum(["in_progress", "completed", "rejected"]).optional().describe("Filter by status"),
|
|
160
|
+
status: z.enum(["in_progress", "completed", "rejected"]).optional().describe("Filter by run status"),
|
|
103
161
|
keyword: z.string().optional().describe("Search keyword"),
|
|
104
|
-
date_range: z.enum(["24h", "7d", "30d", "60d", "custom"]).optional().describe("
|
|
105
|
-
date_from: z.string().optional().describe("Start date
|
|
106
|
-
date_to: z.string().optional().describe("End date
|
|
162
|
+
date_range: z.enum(["24h", "7d", "30d", "60d", "custom"]).optional().describe("Predefined date range filter"),
|
|
163
|
+
date_from: z.string().optional().describe("Start date for custom range"),
|
|
164
|
+
date_to: z.string().optional().describe("End date for custom range"),
|
|
107
165
|
page: z.number().int().positive().optional().describe("Page number"),
|
|
166
|
+
per_page: z.number().int().positive().optional().describe("Results per page"),
|
|
108
167
|
},
|
|
109
168
|
}, withErrorHandling(async (args) => {
|
|
110
169
|
const { id, ...filters } = args;
|
|
@@ -118,4 +177,50 @@ export function registerApprovalFlowTools(server, apiClient) {
|
|
|
118
177
|
const result = await apiClient.get(path);
|
|
119
178
|
return jsonResponse(result);
|
|
120
179
|
}));
|
|
180
|
+
server.registerTool("get_approval_flow_entity", {
|
|
181
|
+
description: "Get details about a specific entity (purchase order or invoice) that went through an approval flow",
|
|
182
|
+
inputSchema: {
|
|
183
|
+
id: z.number().int().positive().describe("Approval Flow ID"),
|
|
184
|
+
entity_id: z.number().int().positive().describe("Entity ID (purchase order or invoice ID)"),
|
|
185
|
+
},
|
|
186
|
+
}, withErrorHandling(async (args) => {
|
|
187
|
+
const path = `${apiClient.buildPath(`/approval_flows/${args.id}/show_entity`)}?entity_id=${args.entity_id}`;
|
|
188
|
+
const result = await apiClient.get(path);
|
|
189
|
+
return jsonResponse(result);
|
|
190
|
+
}));
|
|
191
|
+
server.registerTool("list_approval_flow_versions", {
|
|
192
|
+
description: "List all version history of an approval flow",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
id: z.number().int().positive().describe("Approval Flow ID"),
|
|
195
|
+
},
|
|
196
|
+
}, withErrorHandling(async (args) => {
|
|
197
|
+
const result = await apiClient.get(apiClient.buildPath(`/approval_flows/${args.id}/versions`));
|
|
198
|
+
return jsonResponse(result);
|
|
199
|
+
}));
|
|
200
|
+
server.registerTool("get_approval_flow_version_details", {
|
|
201
|
+
description: "Get full details of a specific version of an approval flow",
|
|
202
|
+
inputSchema: {
|
|
203
|
+
id: z.number().int().positive().describe("Approval Flow ID"),
|
|
204
|
+
version_id: z.number().int().positive().describe("Version ID"),
|
|
205
|
+
},
|
|
206
|
+
}, withErrorHandling(async (args) => {
|
|
207
|
+
const path = `${apiClient.buildPath(`/approval_flows/${args.id}/version_details`)}?version_id=${args.version_id}`;
|
|
208
|
+
const result = await apiClient.get(path);
|
|
209
|
+
return jsonResponse(result);
|
|
210
|
+
}));
|
|
211
|
+
server.registerTool("rerun_approval_flows", {
|
|
212
|
+
description: "Rerun approval flows for specific purchase orders and/or invoices. Useful when approval flow rules have changed and need to be reapplied.",
|
|
213
|
+
inputSchema: {
|
|
214
|
+
order_ids: z.array(z.number().int()).optional().describe("Purchase order IDs to rerun approval flows for"),
|
|
215
|
+
invoice_ids: z.array(z.number().int()).optional().describe("Invoice IDs to rerun approval flows for"),
|
|
216
|
+
},
|
|
217
|
+
}, withErrorHandling(async (args) => {
|
|
218
|
+
const body = {};
|
|
219
|
+
if (args.order_ids)
|
|
220
|
+
body.order_ids = args.order_ids;
|
|
221
|
+
if (args.invoice_ids)
|
|
222
|
+
body.invoice_ids = args.invoice_ids;
|
|
223
|
+
const result = await apiClient.post(apiClient.buildPath("/approval_flows/rerun_approval_flows"), body);
|
|
224
|
+
return jsonResponse(result);
|
|
225
|
+
}));
|
|
121
226
|
}
|
package/dist/tools/budgets.js
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
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
|
export function registerBudgetTools(server, apiClient) {
|
|
4
9
|
server.registerTool("list_budgets", {
|
|
5
|
-
description: "List budgets
|
|
10
|
+
description: "List budgets for the current company. Filter by department and/or archived status. Returns all matching budgets (no pagination).",
|
|
6
11
|
inputSchema: {
|
|
7
|
-
page: z.number().int().positive().optional().describe("Page number (default: 1)"),
|
|
8
|
-
archived: z.boolean().optional().describe("Filter by archived status"),
|
|
9
|
-
only_active: z.boolean().optional().describe("Show only active budgets"),
|
|
10
12
|
department_id: z.number().int().optional().describe("Filter by department ID"),
|
|
13
|
+
archived: z.boolean().optional().describe("Filter by archived status (default: false)"),
|
|
14
|
+
show_mappings: z.boolean().optional().describe("Include third-party ID mappings in response"),
|
|
11
15
|
},
|
|
12
16
|
}, withErrorHandling(async (args) => {
|
|
13
17
|
const params = new URLSearchParams();
|
|
14
|
-
if (args.page)
|
|
15
|
-
params.set("page", String(args.page));
|
|
16
|
-
if (args.archived !== undefined)
|
|
17
|
-
params.set("archived", String(args.archived));
|
|
18
|
-
if (args.only_active)
|
|
19
|
-
params.set("only_active", "true");
|
|
20
18
|
if (args.department_id)
|
|
21
19
|
params.set("department_id", String(args.department_id));
|
|
20
|
+
if (args.archived !== undefined)
|
|
21
|
+
params.set("archived", String(args.archived));
|
|
22
|
+
if (args.show_mappings)
|
|
23
|
+
params.set("show_mappings", "true");
|
|
22
24
|
const query = params.toString();
|
|
23
25
|
const path = `${apiClient.buildPath("/budgets")}${query ? `?${query}` : ""}`;
|
|
24
26
|
const result = await apiClient.get(path);
|
|
25
27
|
return jsonResponse(result);
|
|
26
28
|
}));
|
|
27
29
|
server.registerTool("get_budget", {
|
|
28
|
-
description: "Get a specific budget by ID, including remaining amount",
|
|
30
|
+
description: "Get a specific budget by ID, including remaining amount and associated departments/approvers",
|
|
29
31
|
inputSchema: {
|
|
30
32
|
id: z.number().int().positive().describe("Budget ID"),
|
|
31
33
|
},
|
|
@@ -34,19 +36,22 @@ export function registerBudgetTools(server, apiClient) {
|
|
|
34
36
|
return jsonResponse(budget);
|
|
35
37
|
}));
|
|
36
38
|
server.registerTool("create_budget", {
|
|
37
|
-
description: "Create a new budget",
|
|
39
|
+
description: "Create a new budget. Dates must match the company's date_format setting.",
|
|
38
40
|
inputSchema: {
|
|
39
41
|
name: z.string().describe("Budget name"),
|
|
40
42
|
amount: z.number().describe("Budget amount"),
|
|
41
|
-
currency_id: z.number().int().describe("Currency ID"),
|
|
42
|
-
creator_id: z.number().int().describe("Creator user ID"),
|
|
43
|
+
currency_id: z.number().int().optional().describe("Currency ID (defaults to company currency)"),
|
|
44
|
+
creator_id: z.number().int().optional().describe("Creator user ID"),
|
|
43
45
|
cost_code: z.string().optional().describe("Cost code"),
|
|
44
46
|
cost_type: z.string().optional().describe("Cost type"),
|
|
45
|
-
start_date: z.string().optional().describe("Start date (must match company
|
|
46
|
-
end_date: z.string().optional().describe("End date"),
|
|
47
|
-
allow_anyone_to_approve_a_po: z.boolean().optional().describe("Allow anyone to approve"),
|
|
47
|
+
start_date: z.string().optional().describe("Start date (must match company date_format setting)"),
|
|
48
|
+
end_date: z.string().optional().describe("End date (must match company date_format setting)"),
|
|
49
|
+
allow_anyone_to_approve_a_po: z.boolean().optional().describe("Allow anyone to approve POs against this budget"),
|
|
50
|
+
chart_of_account_id: z.number().int().optional().describe("Chart of account ID (GL code)"),
|
|
51
|
+
qbo_class: z.string().optional().describe("QuickBooks class"),
|
|
48
52
|
approver_ids: z.array(z.number().int()).optional().describe("Approver user IDs"),
|
|
49
|
-
department_ids: z.array(z.number().int()).optional().describe("Department IDs"),
|
|
53
|
+
department_ids: z.array(z.number().int()).optional().describe("Department IDs to associate"),
|
|
54
|
+
custom_field_values_attributes: z.array(customFieldValueSchema).optional().describe("Budget-level custom field values"),
|
|
50
55
|
},
|
|
51
56
|
}, withErrorHandling(async (args) => {
|
|
52
57
|
const budget = await apiClient.post(apiClient.buildPath("/budgets"), { budget: args });
|
|
@@ -58,12 +63,17 @@ export function registerBudgetTools(server, apiClient) {
|
|
|
58
63
|
id: z.number().int().positive().describe("Budget ID"),
|
|
59
64
|
name: z.string().optional().describe("Budget name"),
|
|
60
65
|
amount: z.number().optional().describe("Budget amount"),
|
|
66
|
+
currency_id: z.number().int().optional().describe("Currency ID"),
|
|
61
67
|
cost_code: z.string().optional().describe("Cost code"),
|
|
62
68
|
cost_type: z.string().optional().describe("Cost type"),
|
|
63
|
-
start_date: z.string().optional().describe("Start date"),
|
|
64
|
-
end_date: z.string().optional().describe("End date"),
|
|
69
|
+
start_date: z.string().optional().describe("Start date (must match company date_format setting)"),
|
|
70
|
+
end_date: z.string().optional().describe("End date (must match company date_format setting)"),
|
|
71
|
+
allow_anyone_to_approve_a_po: z.boolean().optional().describe("Allow anyone to approve"),
|
|
72
|
+
chart_of_account_id: z.number().int().optional().describe("Chart of account ID"),
|
|
73
|
+
qbo_class: z.string().optional().describe("QuickBooks class"),
|
|
65
74
|
approver_ids: z.array(z.number().int()).optional().describe("Approver user IDs"),
|
|
66
75
|
department_ids: z.array(z.number().int()).optional().describe("Department IDs"),
|
|
76
|
+
custom_field_values_attributes: z.array(customFieldValueSchema).optional().describe("Budget-level custom field values"),
|
|
67
77
|
},
|
|
68
78
|
}, withErrorHandling(async (args) => {
|
|
69
79
|
const { id, ...data } = args;
|
package/dist/tools/comments.js
CHANGED
|
@@ -2,23 +2,23 @@ import { z } from "zod";
|
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
3
|
export function registerCommentTools(server, apiClient) {
|
|
4
4
|
server.registerTool("add_purchase_order_comment", {
|
|
5
|
-
description: "Add a comment to a purchase order",
|
|
5
|
+
description: "Add a comment to a purchase order. The comment creator is set to the authenticated user.",
|
|
6
6
|
inputSchema: {
|
|
7
7
|
purchase_order_id: z.number().int().positive().describe("Purchase Order ID"),
|
|
8
8
|
comment: z.string().describe("Comment text"),
|
|
9
9
|
},
|
|
10
10
|
}, withErrorHandling(async (args) => {
|
|
11
|
-
const result = await apiClient.post(apiClient.buildPath(`/
|
|
11
|
+
const result = await apiClient.post(apiClient.buildPath(`/purchase_orders/${args.purchase_order_id}/comments`), { comment: args.comment });
|
|
12
12
|
return jsonResponse(result);
|
|
13
13
|
}));
|
|
14
14
|
server.registerTool("add_invoice_comment", {
|
|
15
|
-
description: "Add a comment to an invoice",
|
|
15
|
+
description: "Add a comment to an invoice. The comment creator is set to the authenticated user.",
|
|
16
16
|
inputSchema: {
|
|
17
17
|
invoice_id: z.number().int().positive().describe("Invoice ID"),
|
|
18
18
|
comment: z.string().describe("Comment text"),
|
|
19
19
|
},
|
|
20
20
|
}, withErrorHandling(async (args) => {
|
|
21
|
-
const result = await apiClient.post(apiClient.buildPath(`/invoices/${args.invoice_id}/create_comment`), { comment: args.comment });
|
|
21
|
+
const result = await apiClient.post(apiClient.buildPath(`/invoices/${args.invoice_id}/create_comment`), { invoice_comments: { comment: args.comment } });
|
|
22
22
|
return jsonResponse(result);
|
|
23
23
|
}));
|
|
24
24
|
}
|
package/dist/tools/companies.js
CHANGED
|
@@ -9,7 +9,7 @@ export function registerCompanyTools(server, apiClient) {
|
|
|
9
9
|
return jsonResponse(companies);
|
|
10
10
|
}));
|
|
11
11
|
server.registerTool("get_company", {
|
|
12
|
-
description: "Get company details including settings, custom fields, and supported currencies",
|
|
12
|
+
description: "Get company details by ID including settings, custom fields, and supported currencies",
|
|
13
13
|
inputSchema: {
|
|
14
14
|
id: z.number().int().positive().describe("Company ID"),
|
|
15
15
|
},
|
|
@@ -17,6 +17,13 @@ export function registerCompanyTools(server, apiClient) {
|
|
|
17
17
|
const company = await apiClient.get(apiClient.buildPath(`/companies/${args.id}`));
|
|
18
18
|
return jsonResponse(company);
|
|
19
19
|
}));
|
|
20
|
+
server.registerTool("get_company_details", {
|
|
21
|
+
description: "Get details for the currently active company (set via set_active_company or PROCUREMENTEXPRESS_COMPANY_ID)",
|
|
22
|
+
inputSchema: {},
|
|
23
|
+
}, withErrorHandling(async () => {
|
|
24
|
+
const company = await apiClient.get(apiClient.buildPath("/companies/details"));
|
|
25
|
+
return jsonResponse(company);
|
|
26
|
+
}));
|
|
20
27
|
server.registerTool("set_active_company", {
|
|
21
28
|
description: "Set the active company ID for subsequent API calls. Required before most operations.",
|
|
22
29
|
inputSchema: {
|
|
@@ -27,36 +34,43 @@ export function registerCompanyTools(server, apiClient) {
|
|
|
27
34
|
return textResponse(`Active company set to ${args.company_id}`);
|
|
28
35
|
}));
|
|
29
36
|
server.registerTool("list_approvers", {
|
|
30
|
-
description: "List approvers
|
|
37
|
+
description: "List approvers for the current company. Optionally filter by department. Returns empty if company uses approval flows or has no unassigned budgets.",
|
|
31
38
|
inputSchema: {
|
|
32
|
-
department_id: z.number().int().
|
|
39
|
+
department_id: z.number().int().optional().describe("Filter approvers by department ID"),
|
|
33
40
|
},
|
|
34
41
|
}, withErrorHandling(async (args) => {
|
|
35
|
-
const
|
|
42
|
+
const params = new URLSearchParams();
|
|
43
|
+
if (args.department_id)
|
|
44
|
+
params.set("department_id", String(args.department_id));
|
|
45
|
+
const query = params.toString();
|
|
46
|
+
const path = `${apiClient.buildPath("/companies/approvers")}${query ? `?${query}` : ""}`;
|
|
47
|
+
const approvers = await apiClient.get(path);
|
|
36
48
|
return jsonResponse(approvers);
|
|
37
49
|
}));
|
|
38
50
|
server.registerTool("list_all_approvers", {
|
|
39
|
-
description: "List all approvers regardless of auto-approval routing",
|
|
51
|
+
description: "List all approvers for the current company regardless of auto-approval routing",
|
|
40
52
|
inputSchema: {},
|
|
41
53
|
}, withErrorHandling(async () => {
|
|
42
54
|
const approvers = await apiClient.get(apiClient.buildPath("/companies/all_approvers"));
|
|
43
55
|
return jsonResponse(approvers);
|
|
44
56
|
}));
|
|
45
57
|
server.registerTool("list_employees", {
|
|
46
|
-
description: "List all employees of the current company with their roles",
|
|
58
|
+
description: "List all active employees of the current company with their roles (companyadmin role required)",
|
|
47
59
|
inputSchema: {},
|
|
48
60
|
}, withErrorHandling(async () => {
|
|
49
61
|
const employees = await apiClient.get(apiClient.buildPath("/companies/employees"));
|
|
50
62
|
return jsonResponse(employees);
|
|
51
63
|
}));
|
|
52
64
|
server.registerTool("invite_user", {
|
|
53
|
-
description: "Invite a user to the company. Roles: companyadmin, approver, finance, teammember",
|
|
65
|
+
description: "Invite a user to the company. Roles: companyadmin, approver, finance, teammember. Requires available invite slots on the company plan.",
|
|
54
66
|
inputSchema: {
|
|
55
67
|
email: z.string().email().describe("Email address to invite"),
|
|
56
68
|
name: z.string().describe("Name of the user"),
|
|
57
69
|
roles: z
|
|
58
70
|
.array(z.enum(["companyadmin", "approver", "finance", "teammember"]))
|
|
59
71
|
.describe("Roles to assign"),
|
|
72
|
+
approval_limit: z.number().optional().describe("Approval limit amount (default: 0)"),
|
|
73
|
+
department_ids: z.array(z.number().int()).optional().describe("Department IDs to assign the user to"),
|
|
60
74
|
},
|
|
61
75
|
}, withErrorHandling(async (args) => {
|
|
62
76
|
const result = await apiClient.post(apiClient.buildPath("/companies/send_user_invite"), {
|
|
@@ -64,4 +78,40 @@ export function registerCompanyTools(server, apiClient) {
|
|
|
64
78
|
});
|
|
65
79
|
return jsonResponse(result);
|
|
66
80
|
}));
|
|
81
|
+
server.registerTool("get_invite_limit", {
|
|
82
|
+
description: "Get the remaining invite slots for the current company",
|
|
83
|
+
inputSchema: {},
|
|
84
|
+
}, withErrorHandling(async () => {
|
|
85
|
+
const result = await apiClient.get(apiClient.buildPath("/companies/invite_limit_left"));
|
|
86
|
+
return jsonResponse(result);
|
|
87
|
+
}));
|
|
88
|
+
server.registerTool("list_pending_invites", {
|
|
89
|
+
description: "List pending user invitations for the current company (companyadmin role required)",
|
|
90
|
+
inputSchema: {},
|
|
91
|
+
}, withErrorHandling(async () => {
|
|
92
|
+
const result = await apiClient.get(apiClient.buildPath("/companies/pending_invites"));
|
|
93
|
+
return jsonResponse(result);
|
|
94
|
+
}));
|
|
95
|
+
server.registerTool("cancel_invite", {
|
|
96
|
+
description: "Cancel a pending user invitation (companyadmin role required)",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
token: z.string().describe("Invite token from the pending invite"),
|
|
99
|
+
},
|
|
100
|
+
}, withErrorHandling(async (args) => {
|
|
101
|
+
const result = await apiClient.post(apiClient.buildPath("/companies/cancel_invite"), {
|
|
102
|
+
token: args.token,
|
|
103
|
+
});
|
|
104
|
+
return jsonResponse(result);
|
|
105
|
+
}));
|
|
106
|
+
server.registerTool("resend_invite", {
|
|
107
|
+
description: "Resend a pending user invitation email (companyadmin role required)",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
token: z.string().describe("Invite token from the pending invite"),
|
|
110
|
+
},
|
|
111
|
+
}, withErrorHandling(async (args) => {
|
|
112
|
+
const result = await apiClient.post(apiClient.buildPath("/companies/resend_invite"), {
|
|
113
|
+
token: args.token,
|
|
114
|
+
});
|
|
115
|
+
return jsonResponse(result);
|
|
116
|
+
}));
|
|
67
117
|
}
|
|
@@ -2,10 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { jsonResponse, withErrorHandling } from "../tool-helpers.js";
|
|
3
3
|
export function registerDepartmentTools(server, apiClient) {
|
|
4
4
|
server.registerTool("list_departments", {
|
|
5
|
-
description: "List departments
|
|
5
|
+
description: "List departments. By default returns only departments the current user has access to. Set company_specific=true to list all company departments regardless of user access.",
|
|
6
6
|
inputSchema: {
|
|
7
|
-
archived: z.boolean().optional().describe("Filter by archived status"),
|
|
8
|
-
company_specific: z.boolean().optional().describe("
|
|
7
|
+
archived: z.boolean().optional().describe("Filter by archived status (default: false)"),
|
|
8
|
+
company_specific: z.boolean().optional().describe("True to list all company departments, false/omit for user's departments only"),
|
|
9
9
|
},
|
|
10
10
|
}, withErrorHandling(async (args) => {
|
|
11
11
|
const params = new URLSearchParams();
|
|
@@ -31,9 +31,9 @@ export function registerDepartmentTools(server, apiClient) {
|
|
|
31
31
|
description: "Create a new department",
|
|
32
32
|
inputSchema: {
|
|
33
33
|
name: z.string().describe("Department name"),
|
|
34
|
-
contact_person: z.string().optional().describe("Contact person"),
|
|
34
|
+
contact_person: z.string().optional().describe("Contact person name"),
|
|
35
35
|
phone_number: z.string().optional().describe("Phone number"),
|
|
36
|
-
email: z.string().
|
|
36
|
+
email: z.string().optional().describe("Email address"),
|
|
37
37
|
address: z.string().optional().describe("Address"),
|
|
38
38
|
tax_number: z.string().optional().describe("Tax number"),
|
|
39
39
|
budget_ids: z.array(z.number().int()).optional().describe("Budget IDs to associate"),
|
|
@@ -53,7 +53,7 @@ export function registerDepartmentTools(server, apiClient) {
|
|
|
53
53
|
archived: z.boolean().optional().describe("Archive status"),
|
|
54
54
|
contact_person: z.string().optional().describe("Contact person"),
|
|
55
55
|
phone_number: z.string().optional().describe("Phone number"),
|
|
56
|
-
email: z.string().
|
|
56
|
+
email: z.string().optional().describe("Email"),
|
|
57
57
|
address: z.string().optional().describe("Address"),
|
|
58
58
|
tax_number: z.string().optional().describe("Tax number"),
|
|
59
59
|
budget_ids: z.array(z.number().int()).optional().describe("Budget IDs"),
|