@mangerik/wordpress-mcp 0.1.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/.env.example +32 -0
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/config.d.ts +80 -0
- package/dist/config.js +84 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +145 -0
- package/dist/prompts.d.ts +7 -0
- package/dist/prompts.js +104 -0
- package/dist/resources.d.ts +13 -0
- package/dist/resources.js +64 -0
- package/dist/tools/batch.d.ts +14 -0
- package/dist/tools/batch.js +49 -0
- package/dist/tools/blocks.d.ts +4 -0
- package/dist/tools/blocks.js +202 -0
- package/dist/tools/comments.d.ts +4 -0
- package/dist/tools/comments.js +80 -0
- package/dist/tools/cpt.d.ts +16 -0
- package/dist/tools/cpt.js +97 -0
- package/dist/tools/jwt.d.ts +9 -0
- package/dist/tools/jwt.js +17 -0
- package/dist/tools/media.d.ts +4 -0
- package/dist/tools/media.js +101 -0
- package/dist/tools/multisite.d.ts +17 -0
- package/dist/tools/multisite.js +111 -0
- package/dist/tools/pages.d.ts +4 -0
- package/dist/tools/pages.js +101 -0
- package/dist/tools/posts.d.ts +4 -0
- package/dist/tools/posts.js +160 -0
- package/dist/tools/seo.d.ts +4 -0
- package/dist/tools/seo.js +269 -0
- package/dist/tools/site.d.ts +4 -0
- package/dist/tools/site.js +96 -0
- package/dist/tools/taxonomy.d.ts +4 -0
- package/dist/tools/taxonomy.js +147 -0
- package/dist/tools/users.d.ts +4 -0
- package/dist/tools/users.js +99 -0
- package/dist/tools/woocommerce.d.ts +4 -0
- package/dist/tools/woocommerce.js +400 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.js +2 -0
- package/dist/wordpress-client.d.ts +223 -0
- package/dist/wordpress-client.js +519 -0
- package/package.json +67 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* WooCommerce REST API tools (namespace `wc/v3`).
|
|
4
|
+
*
|
|
5
|
+
* Auth: if WC_CONSUMER_KEY / WC_CONSUMER_SECRET are configured the client
|
|
6
|
+
* automatically uses them for /wc/* routes; otherwise it falls back to the
|
|
7
|
+
* Application Password (the WP user must have `manage_woocommerce`).
|
|
8
|
+
*
|
|
9
|
+
* Coverage: products, product variations, orders, customers, coupons,
|
|
10
|
+
* categories, refunds, reports. For anything else, use the generic
|
|
11
|
+
* `wp_list_items` / `wp_create_item` tools with route `wc/v3/...`.
|
|
12
|
+
*/
|
|
13
|
+
const orderEnum = z.enum(["asc", "desc"]);
|
|
14
|
+
// ─── Products ─────────────────────────────────────────────────────────────
|
|
15
|
+
const productListSchema = {
|
|
16
|
+
page: z.number().int().positive().optional(),
|
|
17
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
18
|
+
search: z.string().optional(),
|
|
19
|
+
status: z.enum(["any", "draft", "pending", "private", "publish"]).optional(),
|
|
20
|
+
type: z.enum(["simple", "grouped", "external", "variable"]).optional(),
|
|
21
|
+
category: z.string().optional().describe("Category slug"),
|
|
22
|
+
tag: z.string().optional().describe("Tag slug"),
|
|
23
|
+
sku: z.string().optional(),
|
|
24
|
+
featured: z.boolean().optional(),
|
|
25
|
+
on_sale: z.boolean().optional(),
|
|
26
|
+
min_price: z.string().optional(),
|
|
27
|
+
max_price: z.string().optional(),
|
|
28
|
+
stock_status: z.enum(["instock", "outofstock", "onbackorder"]).optional(),
|
|
29
|
+
orderby: z
|
|
30
|
+
.enum(["date", "id", "include", "title", "slug", "price", "popularity", "rating"])
|
|
31
|
+
.optional(),
|
|
32
|
+
order: orderEnum.optional(),
|
|
33
|
+
after: z.string().optional(),
|
|
34
|
+
before: z.string().optional(),
|
|
35
|
+
_fields: z.string().optional(),
|
|
36
|
+
};
|
|
37
|
+
const productCreateSchema = {
|
|
38
|
+
name: z.string().min(1),
|
|
39
|
+
type: z.enum(["simple", "grouped", "external", "variable"]).optional(),
|
|
40
|
+
regular_price: z.string().optional(),
|
|
41
|
+
sale_price: z.string().optional(),
|
|
42
|
+
description: z.string().optional(),
|
|
43
|
+
short_description: z.string().optional(),
|
|
44
|
+
sku: z.string().optional(),
|
|
45
|
+
status: z.enum(["draft", "pending", "private", "publish"]).optional(),
|
|
46
|
+
featured: z.boolean().optional(),
|
|
47
|
+
catalog_visibility: z.enum(["visible", "catalog", "search", "hidden"]).optional(),
|
|
48
|
+
manage_stock: z.boolean().optional(),
|
|
49
|
+
stock_quantity: z.number().int().optional(),
|
|
50
|
+
stock_status: z.enum(["instock", "outofstock", "onbackorder"]).optional(),
|
|
51
|
+
weight: z.string().optional(),
|
|
52
|
+
dimensions: z
|
|
53
|
+
.object({
|
|
54
|
+
length: z.string().optional(),
|
|
55
|
+
width: z.string().optional(),
|
|
56
|
+
height: z.string().optional(),
|
|
57
|
+
})
|
|
58
|
+
.optional(),
|
|
59
|
+
categories: z.array(z.object({ id: z.number().int() })).optional(),
|
|
60
|
+
tags: z.array(z.object({ id: z.number().int() })).optional(),
|
|
61
|
+
images: z
|
|
62
|
+
.array(z.object({
|
|
63
|
+
id: z.number().int().optional(),
|
|
64
|
+
src: z.string().url().optional(),
|
|
65
|
+
alt: z.string().optional(),
|
|
66
|
+
name: z.string().optional(),
|
|
67
|
+
}))
|
|
68
|
+
.optional(),
|
|
69
|
+
attributes: z
|
|
70
|
+
.array(z.object({
|
|
71
|
+
id: z.number().int().optional(),
|
|
72
|
+
name: z.string().optional(),
|
|
73
|
+
position: z.number().int().optional(),
|
|
74
|
+
visible: z.boolean().optional(),
|
|
75
|
+
variation: z.boolean().optional(),
|
|
76
|
+
options: z.array(z.string()).optional(),
|
|
77
|
+
}))
|
|
78
|
+
.optional(),
|
|
79
|
+
meta_data: z
|
|
80
|
+
.array(z.object({ key: z.string(), value: z.unknown() }))
|
|
81
|
+
.optional(),
|
|
82
|
+
};
|
|
83
|
+
// ─── Orders ───────────────────────────────────────────────────────────────
|
|
84
|
+
const orderStatus = z.enum([
|
|
85
|
+
"any",
|
|
86
|
+
"pending",
|
|
87
|
+
"processing",
|
|
88
|
+
"on-hold",
|
|
89
|
+
"completed",
|
|
90
|
+
"cancelled",
|
|
91
|
+
"refunded",
|
|
92
|
+
"failed",
|
|
93
|
+
"trash",
|
|
94
|
+
]);
|
|
95
|
+
const orderListSchema = {
|
|
96
|
+
page: z.number().int().positive().optional(),
|
|
97
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
98
|
+
search: z.string().optional(),
|
|
99
|
+
status: orderStatus.optional(),
|
|
100
|
+
customer: z.number().int().optional(),
|
|
101
|
+
product: z.number().int().optional(),
|
|
102
|
+
after: z.string().optional(),
|
|
103
|
+
before: z.string().optional(),
|
|
104
|
+
orderby: z.enum(["date", "id", "include", "title", "slug"]).optional(),
|
|
105
|
+
order: orderEnum.optional(),
|
|
106
|
+
_fields: z.string().optional(),
|
|
107
|
+
};
|
|
108
|
+
// ─── Tools ────────────────────────────────────────────────────────────────
|
|
109
|
+
export const woocommerceTools = (wp) => [
|
|
110
|
+
// ── Products ───────────────────────────────────────────────────────────
|
|
111
|
+
{
|
|
112
|
+
name: "wc_list_products",
|
|
113
|
+
title: "WC: list products",
|
|
114
|
+
description: "List WooCommerce products with filters.",
|
|
115
|
+
inputSchema: productListSchema,
|
|
116
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
117
|
+
handler: async (input) => {
|
|
118
|
+
const r = await wp.list("wc/v3/products", input);
|
|
119
|
+
return { products: r.data, total: r.total, total_pages: r.pages };
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "wc_get_product",
|
|
124
|
+
title: "WC: get product",
|
|
125
|
+
description: "Get a single product by ID.",
|
|
126
|
+
inputSchema: { id: z.number().int().positive() },
|
|
127
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
128
|
+
handler: async (input) => wp.get("wc/v3/products", input.id),
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "wc_create_product",
|
|
132
|
+
title: "WC: create product",
|
|
133
|
+
description: "Create a new WooCommerce product.",
|
|
134
|
+
inputSchema: productCreateSchema,
|
|
135
|
+
annotations: { openWorldHint: true },
|
|
136
|
+
handler: async (input) => wp.create("wc/v3/products", input),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "wc_update_product",
|
|
140
|
+
title: "WC: update product",
|
|
141
|
+
description: "Update a WooCommerce product.",
|
|
142
|
+
inputSchema: { id: z.number().int().positive(), ...productCreateSchema },
|
|
143
|
+
annotations: { openWorldHint: true },
|
|
144
|
+
handler: async (input) => {
|
|
145
|
+
const { id, ...data } = input;
|
|
146
|
+
// All productCreateSchema fields are required at the top level, but
|
|
147
|
+
// for updates we want them optional. Strip undefined explicitly so
|
|
148
|
+
// we don't send them. (Zod already drops undefined; keep cast safe.)
|
|
149
|
+
return wp.update("wc/v3/products", id, data);
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "wc_delete_product",
|
|
154
|
+
title: "WC: delete product",
|
|
155
|
+
description: "Delete a WooCommerce product. force=true is irreversible (skips trash).",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
id: z.number().int().positive(),
|
|
158
|
+
force: z.boolean().optional(),
|
|
159
|
+
},
|
|
160
|
+
annotations: { destructiveHint: true, openWorldHint: true },
|
|
161
|
+
handler: async (input) => {
|
|
162
|
+
const { id, force = false } = input;
|
|
163
|
+
return wp.remove("wc/v3/products", id, force);
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
// ── Product variations ─────────────────────────────────────────────────
|
|
167
|
+
{
|
|
168
|
+
name: "wc_list_variations",
|
|
169
|
+
title: "WC: list product variations",
|
|
170
|
+
description: "List variations of a variable product.",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
product_id: z.number().int().positive(),
|
|
173
|
+
page: z.number().int().positive().optional(),
|
|
174
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
175
|
+
_fields: z.string().optional(),
|
|
176
|
+
},
|
|
177
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
178
|
+
handler: async (input) => {
|
|
179
|
+
const { product_id, ...rest } = input;
|
|
180
|
+
const r = await wp.list(`wc/v3/products/${product_id}/variations`, rest);
|
|
181
|
+
return { variations: r.data, total: r.total };
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "wc_create_variation",
|
|
186
|
+
title: "WC: create product variation",
|
|
187
|
+
description: "Create a variation under a variable product.",
|
|
188
|
+
inputSchema: {
|
|
189
|
+
product_id: z.number().int().positive(),
|
|
190
|
+
regular_price: z.string().optional(),
|
|
191
|
+
sale_price: z.string().optional(),
|
|
192
|
+
sku: z.string().optional(),
|
|
193
|
+
stock_quantity: z.number().int().optional(),
|
|
194
|
+
attributes: z
|
|
195
|
+
.array(z.object({ id: z.number().int().optional(), name: z.string().optional(), option: z.string() }))
|
|
196
|
+
.optional(),
|
|
197
|
+
image: z.object({ id: z.number().int().optional(), src: z.string().url().optional() }).optional(),
|
|
198
|
+
},
|
|
199
|
+
annotations: { openWorldHint: true },
|
|
200
|
+
handler: async (input) => {
|
|
201
|
+
const { product_id, ...body } = input;
|
|
202
|
+
return wp.create(`wc/v3/products/${product_id}/variations`, body);
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
// ── Categories ─────────────────────────────────────────────────────────
|
|
206
|
+
{
|
|
207
|
+
name: "wc_list_product_categories",
|
|
208
|
+
title: "WC: list product categories",
|
|
209
|
+
description: "List WooCommerce product categories.",
|
|
210
|
+
inputSchema: {
|
|
211
|
+
page: z.number().int().positive().optional(),
|
|
212
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
213
|
+
search: z.string().optional(),
|
|
214
|
+
hide_empty: z.boolean().optional(),
|
|
215
|
+
parent: z.number().int().optional(),
|
|
216
|
+
orderby: z.enum(["id", "include", "name", "slug", "term_group", "description", "count"]).optional(),
|
|
217
|
+
order: orderEnum.optional(),
|
|
218
|
+
},
|
|
219
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
220
|
+
handler: async (input) => {
|
|
221
|
+
const r = await wp.list("wc/v3/products/categories", input);
|
|
222
|
+
return { categories: r.data, total: r.total };
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
// ── Orders ─────────────────────────────────────────────────────────────
|
|
226
|
+
{
|
|
227
|
+
name: "wc_list_orders",
|
|
228
|
+
title: "WC: list orders",
|
|
229
|
+
description: "List WooCommerce orders.",
|
|
230
|
+
inputSchema: orderListSchema,
|
|
231
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
232
|
+
handler: async (input) => {
|
|
233
|
+
const r = await wp.list("wc/v3/orders", input);
|
|
234
|
+
return { orders: r.data, total: r.total, total_pages: r.pages };
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: "wc_get_order",
|
|
239
|
+
title: "WC: get order",
|
|
240
|
+
description: "Get a single order by ID.",
|
|
241
|
+
inputSchema: { id: z.number().int().positive() },
|
|
242
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
243
|
+
handler: async (input) => wp.get("wc/v3/orders", input.id),
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "wc_update_order",
|
|
247
|
+
title: "WC: update order",
|
|
248
|
+
description: "Update an order — most commonly used to change status.",
|
|
249
|
+
inputSchema: {
|
|
250
|
+
id: z.number().int().positive(),
|
|
251
|
+
status: orderStatus.optional(),
|
|
252
|
+
customer_note: z.string().optional(),
|
|
253
|
+
transaction_id: z.string().optional(),
|
|
254
|
+
meta_data: z.array(z.object({ key: z.string(), value: z.unknown() })).optional(),
|
|
255
|
+
},
|
|
256
|
+
annotations: { openWorldHint: true },
|
|
257
|
+
handler: async (input) => {
|
|
258
|
+
const { id, ...data } = input;
|
|
259
|
+
return wp.update("wc/v3/orders", id, data);
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "wc_create_order_note",
|
|
264
|
+
title: "WC: add note to an order",
|
|
265
|
+
description: "Add a note (private or customer-facing) to an order.",
|
|
266
|
+
inputSchema: {
|
|
267
|
+
order_id: z.number().int().positive(),
|
|
268
|
+
note: z.string().min(1),
|
|
269
|
+
customer_note: z.boolean().optional().describe("If true, visible to customer."),
|
|
270
|
+
},
|
|
271
|
+
annotations: { openWorldHint: true },
|
|
272
|
+
handler: async (input) => {
|
|
273
|
+
const { order_id, ...body } = input;
|
|
274
|
+
return wp.create(`wc/v3/orders/${order_id}/notes`, body);
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: "wc_create_refund",
|
|
279
|
+
title: "WC: create order refund",
|
|
280
|
+
description: "Create a refund for an order.",
|
|
281
|
+
inputSchema: {
|
|
282
|
+
order_id: z.number().int().positive(),
|
|
283
|
+
amount: z.string().describe("Refund amount as decimal string, e.g. '12.50'"),
|
|
284
|
+
reason: z.string().optional(),
|
|
285
|
+
api_refund: z.boolean().optional().describe("Trigger payment gateway refund."),
|
|
286
|
+
line_items: z
|
|
287
|
+
.array(z.object({
|
|
288
|
+
id: z.number().int(),
|
|
289
|
+
quantity: z.number().int().optional(),
|
|
290
|
+
refund_total: z.number().optional(),
|
|
291
|
+
}))
|
|
292
|
+
.optional(),
|
|
293
|
+
},
|
|
294
|
+
annotations: { destructiveHint: true, openWorldHint: true },
|
|
295
|
+
handler: async (input) => {
|
|
296
|
+
const { order_id, ...body } = input;
|
|
297
|
+
return wp.create(`wc/v3/orders/${order_id}/refunds`, body);
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
// ── Customers ──────────────────────────────────────────────────────────
|
|
301
|
+
{
|
|
302
|
+
name: "wc_list_customers",
|
|
303
|
+
title: "WC: list customers",
|
|
304
|
+
description: "List WooCommerce customers.",
|
|
305
|
+
inputSchema: {
|
|
306
|
+
page: z.number().int().positive().optional(),
|
|
307
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
308
|
+
search: z.string().optional(),
|
|
309
|
+
email: z.string().email().optional(),
|
|
310
|
+
role: z.string().optional(),
|
|
311
|
+
orderby: z.enum(["id", "include", "name", "registered_date"]).optional(),
|
|
312
|
+
order: orderEnum.optional(),
|
|
313
|
+
},
|
|
314
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
315
|
+
handler: async (input) => {
|
|
316
|
+
const r = await wp.list("wc/v3/customers", input);
|
|
317
|
+
return { customers: r.data, total: r.total };
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
name: "wc_get_customer",
|
|
322
|
+
title: "WC: get customer",
|
|
323
|
+
description: "Get a single customer by ID.",
|
|
324
|
+
inputSchema: { id: z.number().int().positive() },
|
|
325
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
326
|
+
handler: async (input) => wp.get("wc/v3/customers", input.id),
|
|
327
|
+
},
|
|
328
|
+
// ── Coupons ────────────────────────────────────────────────────────────
|
|
329
|
+
{
|
|
330
|
+
name: "wc_list_coupons",
|
|
331
|
+
title: "WC: list coupons",
|
|
332
|
+
description: "List WooCommerce coupons.",
|
|
333
|
+
inputSchema: {
|
|
334
|
+
page: z.number().int().positive().optional(),
|
|
335
|
+
per_page: z.number().int().min(1).max(100).optional(),
|
|
336
|
+
search: z.string().optional(),
|
|
337
|
+
code: z.string().optional(),
|
|
338
|
+
},
|
|
339
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
340
|
+
handler: async (input) => {
|
|
341
|
+
const r = await wp.list("wc/v3/coupons", input);
|
|
342
|
+
return { coupons: r.data, total: r.total };
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "wc_create_coupon",
|
|
347
|
+
title: "WC: create coupon",
|
|
348
|
+
description: "Create a new coupon.",
|
|
349
|
+
inputSchema: {
|
|
350
|
+
code: z.string().min(1),
|
|
351
|
+
discount_type: z.enum(["percent", "fixed_cart", "fixed_product"]).optional(),
|
|
352
|
+
amount: z.string().optional(),
|
|
353
|
+
individual_use: z.boolean().optional(),
|
|
354
|
+
exclude_sale_items: z.boolean().optional(),
|
|
355
|
+
minimum_amount: z.string().optional(),
|
|
356
|
+
maximum_amount: z.string().optional(),
|
|
357
|
+
usage_limit: z.number().int().optional(),
|
|
358
|
+
usage_limit_per_user: z.number().int().optional(),
|
|
359
|
+
date_expires: z.string().optional(),
|
|
360
|
+
product_ids: z.array(z.number().int()).optional(),
|
|
361
|
+
excluded_product_ids: z.array(z.number().int()).optional(),
|
|
362
|
+
free_shipping: z.boolean().optional(),
|
|
363
|
+
description: z.string().optional(),
|
|
364
|
+
},
|
|
365
|
+
annotations: { openWorldHint: true },
|
|
366
|
+
handler: async (input) => wp.create("wc/v3/coupons", input),
|
|
367
|
+
},
|
|
368
|
+
// ── Reports ────────────────────────────────────────────────────────────
|
|
369
|
+
{
|
|
370
|
+
name: "wc_get_sales_report",
|
|
371
|
+
title: "WC: sales report",
|
|
372
|
+
description: "Get a sales summary report.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
period: z.enum(["week", "month", "last_month", "year"]).optional(),
|
|
375
|
+
date_min: z.string().optional().describe("ISO date YYYY-MM-DD"),
|
|
376
|
+
date_max: z.string().optional().describe("ISO date YYYY-MM-DD"),
|
|
377
|
+
},
|
|
378
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
379
|
+
handler: async (input) => {
|
|
380
|
+
const r = await wp.list("wc/v3/reports/sales", input);
|
|
381
|
+
return { report: r.data };
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "wc_get_top_sellers",
|
|
386
|
+
title: "WC: top sellers report",
|
|
387
|
+
description: "Get top-selling products.",
|
|
388
|
+
inputSchema: {
|
|
389
|
+
period: z.enum(["week", "month", "last_month", "year"]).optional(),
|
|
390
|
+
date_min: z.string().optional(),
|
|
391
|
+
date_max: z.string().optional(),
|
|
392
|
+
},
|
|
393
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
394
|
+
handler: async (input) => {
|
|
395
|
+
const r = await wp.list("wc/v3/reports/top_sellers", input);
|
|
396
|
+
return { top_sellers: r.data };
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
//# sourceMappingURL=woocommerce.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ZodRawShape } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Shape of an MCP tool definition used internally.
|
|
4
|
+
* The handler returns any plain JS value; the runner will wrap it
|
|
5
|
+
* into a proper CallToolResult ({ content, structuredContent, isError }).
|
|
6
|
+
*/
|
|
7
|
+
export interface ToolDef<Shape extends ZodRawShape = ZodRawShape> {
|
|
8
|
+
name: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
description: string;
|
|
11
|
+
/** Raw zod shape (not z.object). The MCP SDK will build the JSON schema. */
|
|
12
|
+
inputSchema: Shape;
|
|
13
|
+
/** Handler receives validated input, returns plain JS value or throws. */
|
|
14
|
+
handler: (input: Record<string, unknown>) => Promise<unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Hint about side effects, used by clients to decide whether to ask
|
|
17
|
+
* the user for confirmation before executing.
|
|
18
|
+
*/
|
|
19
|
+
annotations?: {
|
|
20
|
+
readOnlyHint?: boolean;
|
|
21
|
+
destructiveHint?: boolean;
|
|
22
|
+
idempotentHint?: boolean;
|
|
23
|
+
openWorldHint?: boolean;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
export interface WordPressConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
/** Auth mode. Defaults to "application_password". */
|
|
4
|
+
authMode?: "application_password" | "jwt";
|
|
5
|
+
/** WP username (required for application_password and JWT bootstrap). */
|
|
6
|
+
username?: string;
|
|
7
|
+
/** Application password (application_password mode). */
|
|
8
|
+
appPassword?: string;
|
|
9
|
+
/** WP password (jwt mode bootstrap). */
|
|
10
|
+
password?: string;
|
|
11
|
+
/** Pre-issued JWT (skip token fetch). */
|
|
12
|
+
jwtToken?: string;
|
|
13
|
+
/** REST namespace for the JWT plugin. Default 'jwt-auth/v1'. */
|
|
14
|
+
jwtNamespace?: string;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
maxRetries?: number;
|
|
17
|
+
verifySsl?: boolean;
|
|
18
|
+
userAgent?: string;
|
|
19
|
+
/** Optional WooCommerce consumer key for /wc/* and /wc-analytics/* routes. */
|
|
20
|
+
wcConsumerKey?: string;
|
|
21
|
+
/** Optional WooCommerce consumer secret. */
|
|
22
|
+
wcConsumerSecret?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Common WP REST query parameters. Anything not covered here can be passed
|
|
26
|
+
* via the `extra` field of higher-level tool wrappers.
|
|
27
|
+
*/
|
|
28
|
+
export interface WPQueryParams {
|
|
29
|
+
page?: number;
|
|
30
|
+
per_page?: number;
|
|
31
|
+
search?: string;
|
|
32
|
+
orderby?: string;
|
|
33
|
+
order?: "asc" | "desc";
|
|
34
|
+
status?: string;
|
|
35
|
+
categories?: number[] | string;
|
|
36
|
+
tags?: number[] | string;
|
|
37
|
+
author?: number | number[];
|
|
38
|
+
after?: string;
|
|
39
|
+
before?: string;
|
|
40
|
+
slug?: string | string[];
|
|
41
|
+
include?: number[];
|
|
42
|
+
exclude?: number[];
|
|
43
|
+
parent?: number | number[];
|
|
44
|
+
context?: "view" | "embed" | "edit";
|
|
45
|
+
/** Comma-separated list of fields to keep in the response (saves tokens). */
|
|
46
|
+
_fields?: string;
|
|
47
|
+
/** Embed related entities like author, featured_media. */
|
|
48
|
+
_embed?: boolean | string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface WPListResult<T> {
|
|
52
|
+
data: T[];
|
|
53
|
+
total: number;
|
|
54
|
+
pages: number;
|
|
55
|
+
}
|
|
56
|
+
export declare class WordPressClient {
|
|
57
|
+
readonly baseUrl: string;
|
|
58
|
+
private readonly client;
|
|
59
|
+
private readonly maxRetries;
|
|
60
|
+
private readonly userAgent;
|
|
61
|
+
private readonly wcKey?;
|
|
62
|
+
private readonly wcSecret?;
|
|
63
|
+
private readonly authMode;
|
|
64
|
+
private readonly jwtNamespace;
|
|
65
|
+
private readonly username?;
|
|
66
|
+
private readonly password?;
|
|
67
|
+
private jwtToken?;
|
|
68
|
+
constructor(config: WordPressConfig);
|
|
69
|
+
/**
|
|
70
|
+
* Ensure a usable JWT is loaded. Called once at startup (or on demand)
|
|
71
|
+
* by callers in JWT mode without a pre-issued token.
|
|
72
|
+
*/
|
|
73
|
+
ensureJwt(): Promise<void>;
|
|
74
|
+
private buildQuery;
|
|
75
|
+
/**
|
|
76
|
+
* Wrap axios request with retry on transient errors and structured error
|
|
77
|
+
* formatting that surfaces WordPress' own `code`/`message` fields.
|
|
78
|
+
*/
|
|
79
|
+
private request;
|
|
80
|
+
private backoffMs;
|
|
81
|
+
private sleep;
|
|
82
|
+
/**
|
|
83
|
+
* If the request targets WooCommerce (/wc/* or /wc-analytics/*) AND
|
|
84
|
+
* Consumer Key/Secret are configured, attach them as query params and
|
|
85
|
+
* strip the Authorization header. WC accepts CK/CS over HTTPS as basic
|
|
86
|
+
* params; we always assume HTTPS and rely on TLS for confidentiality.
|
|
87
|
+
*/
|
|
88
|
+
private applyWcAuth;
|
|
89
|
+
private toError;
|
|
90
|
+
/**
|
|
91
|
+
* Generic list call. `route` is e.g. "wp/v2/posts" or "wc/v3/products".
|
|
92
|
+
*/
|
|
93
|
+
list<T = unknown>(route: string, params?: WPQueryParams): Promise<WPListResult<T>>;
|
|
94
|
+
get<T = unknown>(route: string, id: number, params?: WPQueryParams): Promise<T>;
|
|
95
|
+
create<T = unknown>(route: string, body: Record<string, unknown>): Promise<T>;
|
|
96
|
+
update<T = unknown>(route: string, id: number, body: Record<string, unknown>): Promise<T>;
|
|
97
|
+
remove<T = unknown>(route: string, id: number, force?: boolean): Promise<T>;
|
|
98
|
+
/**
|
|
99
|
+
* Low-level escape hatch: send an arbitrary GET / POST to a fully
|
|
100
|
+
* specified path. Used by tools that work with string IDs (e.g. block
|
|
101
|
+
* templates) or non-`wp/v2` routes that don't fit list/get/create/update.
|
|
102
|
+
*/
|
|
103
|
+
raw<T = unknown>(opts: {
|
|
104
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS";
|
|
105
|
+
path: string;
|
|
106
|
+
query?: WPQueryParams;
|
|
107
|
+
body?: Record<string, unknown>;
|
|
108
|
+
}): Promise<T>;
|
|
109
|
+
posts: {
|
|
110
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
111
|
+
get: (id: number, p?: WPQueryParams) => Promise<unknown>;
|
|
112
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
113
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
114
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
115
|
+
revisions: (id: number, p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
116
|
+
};
|
|
117
|
+
pages: {
|
|
118
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
119
|
+
get: (id: number, p?: WPQueryParams) => Promise<unknown>;
|
|
120
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
121
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
122
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
123
|
+
};
|
|
124
|
+
media: {
|
|
125
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
126
|
+
get: (id: number) => Promise<unknown>;
|
|
127
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
128
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
129
|
+
};
|
|
130
|
+
categories: {
|
|
131
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
132
|
+
get: (id: number) => Promise<unknown>;
|
|
133
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
134
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
135
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
136
|
+
};
|
|
137
|
+
tags: {
|
|
138
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
139
|
+
get: (id: number) => Promise<unknown>;
|
|
140
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
141
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
142
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
143
|
+
};
|
|
144
|
+
comments: {
|
|
145
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
146
|
+
get: (id: number) => Promise<unknown>;
|
|
147
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
148
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
149
|
+
remove: (id: number, force?: boolean) => Promise<unknown>;
|
|
150
|
+
};
|
|
151
|
+
users: {
|
|
152
|
+
list: (p?: WPQueryParams) => Promise<WPListResult<unknown>>;
|
|
153
|
+
get: (id: number) => Promise<unknown>;
|
|
154
|
+
me: () => Promise<unknown>;
|
|
155
|
+
create: (body: Record<string, unknown>) => Promise<unknown>;
|
|
156
|
+
update: (id: number, body: Record<string, unknown>) => Promise<unknown>;
|
|
157
|
+
remove: (id: number, reassignTo: number) => Promise<unknown>;
|
|
158
|
+
};
|
|
159
|
+
siteInfo(): Promise<any>;
|
|
160
|
+
settings(): Promise<unknown>;
|
|
161
|
+
updateSettings(body: Record<string, unknown>): Promise<unknown>;
|
|
162
|
+
types(): Promise<unknown>;
|
|
163
|
+
taxonomies(): Promise<unknown>;
|
|
164
|
+
search(query: string, params?: {
|
|
165
|
+
type?: string;
|
|
166
|
+
subtype?: string;
|
|
167
|
+
page?: number;
|
|
168
|
+
per_page?: number;
|
|
169
|
+
}): Promise<{
|
|
170
|
+
data: unknown[];
|
|
171
|
+
total: number;
|
|
172
|
+
}>;
|
|
173
|
+
uploadMediaFromFile(filePath: string, metadata?: {
|
|
174
|
+
title?: string;
|
|
175
|
+
alt_text?: string;
|
|
176
|
+
caption?: string;
|
|
177
|
+
description?: string;
|
|
178
|
+
post?: number;
|
|
179
|
+
}): Promise<unknown>;
|
|
180
|
+
uploadMediaFromUrl(fileUrl: string, metadata?: {
|
|
181
|
+
title?: string;
|
|
182
|
+
alt_text?: string;
|
|
183
|
+
caption?: string;
|
|
184
|
+
description?: string;
|
|
185
|
+
post?: number;
|
|
186
|
+
}): Promise<unknown>;
|
|
187
|
+
/**
|
|
188
|
+
* Discover the batch endpoint capabilities. Returns the parsed OPTIONS body
|
|
189
|
+
* which contains `endpoints[0].args.requests.maxItems` (default 25).
|
|
190
|
+
*/
|
|
191
|
+
batchOptions(): Promise<unknown>;
|
|
192
|
+
/**
|
|
193
|
+
* Send a batch of write operations to /batch/v1.
|
|
194
|
+
* GET is not supported by core; only POST/PUT/PATCH/DELETE.
|
|
195
|
+
*/
|
|
196
|
+
batch(requests: Array<{
|
|
197
|
+
method?: "POST" | "PUT" | "PATCH" | "DELETE";
|
|
198
|
+
path: string;
|
|
199
|
+
headers?: Record<string, string | string[]>;
|
|
200
|
+
body?: Record<string, unknown>;
|
|
201
|
+
}>, validation?: "normal" | "require-all-validate"): Promise<{
|
|
202
|
+
failed?: string;
|
|
203
|
+
responses: Array<unknown>;
|
|
204
|
+
}>;
|
|
205
|
+
/** Validate the current JWT against /token/validate. */
|
|
206
|
+
validateJwt(): Promise<unknown>;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Custom error class that carries the WP REST API error code & status.
|
|
210
|
+
* Tool runners convert this to MCP `isError` results.
|
|
211
|
+
*/
|
|
212
|
+
export declare class WPError extends Error {
|
|
213
|
+
status: number;
|
|
214
|
+
code: string;
|
|
215
|
+
details?: unknown;
|
|
216
|
+
constructor(message: string, opts: {
|
|
217
|
+
status: number;
|
|
218
|
+
code: string;
|
|
219
|
+
details?: unknown;
|
|
220
|
+
cause?: unknown;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=wordpress-client.d.ts.map
|