#!/usr/bin/env node
import axios from "axios";
import { createInterface } from "readline";
import { WooMetaData } from "./types";
interface JsonRpcRequest {
jsonrpc: "2.0";
id: string | number;
method: string;
params?: any;
}
interface JsonRpcResponse {
jsonrpc: "2.0";
id: string | number;
result?: any;
error?: {
code: number;
message: string;
data?: any;
};
}
interface WordPressError {
message: string;
code?: string;
}
type AxiosError = {
response?: {
data?: WordPressError;
};
message: string;
};
const isAxiosError = (error: unknown): error is AxiosError => {
return (
error !== null &&
typeof error === "object" &&
"message" in error &&
(error as any).response !== undefined
);
};
// Get WordPress credentials from environment variables
const DEFAULT_SITE_URL = process.env.WORDPRESS_SITE_URL || "";
const DEFAULT_USERNAME = process.env.WORDPRESS_USERNAME || "";
const DEFAULT_PASSWORD = process.env.WORDPRESS_PASSWORD || "";
const DEFAULT_CONSUMER_KEY = process.env.WOOCOMMERCE_CONSUMER_KEY || "";
const DEFAULT_CONSUMER_SECRET = process.env.WOOCOMMERCE_CONSUMER_SECRET || "";
async function handleWooCommerceRequest(
method: string,
params: any
): Promise<any> {
try {
const siteUrl = params.siteUrl || DEFAULT_SITE_URL;
const username = params.username || DEFAULT_USERNAME;
const password = params.password || DEFAULT_PASSWORD;
const consumerKey = params.consumerKey || DEFAULT_CONSUMER_KEY;
const consumerSecret = params.consumerSecret || DEFAULT_CONSUMER_SECRET;
if (!siteUrl) {
throw new Error(
"WordPress site URL not provided in environment variables or request parameters"
);
}
// For standard WordPress API endpoints
const wpMethods = [
"create_post",
"get_posts",
"update_post",
"get_post_meta",
"update_post_meta",
"create_post_meta",
"delete_post_meta",
];
// For WooCommerce API endpoints
const wooMethods = [
"get_products",
"get_product",
"create_product",
"update_product",
"delete_product",
"get_orders",
"get_order",
"create_order",
"update_order",
"delete_order",
"get_customers",
"get_customer",
"create_customer",
"update_customer",
"delete_customer",
"get_sales_report",
"get_products_report",
"get_orders_report",
"get_categories_report",
"get_customers_report",
"get_stock_report",
"get_coupons_report",
"get_taxes_report",
// Shipping methods
"get_shipping_zones",
"get_shipping_zone",
"create_shipping_zone",
"update_shipping_zone",
"delete_shipping_zone",
"get_shipping_methods",
"get_shipping_zone_methods",
"create_shipping_zone_method",
"update_shipping_zone_method",
"delete_shipping_zone_method",
"get_shipping_zone_locations",
"update_shipping_zone_locations",
// Tax settings
"get_tax_classes",
"create_tax_class",
"delete_tax_class",
"get_tax_rates",
"get_tax_rate",
"create_tax_rate",
"update_tax_rate",
"delete_tax_rate",
// Discount/Coupon settings
"get_coupons",
"get_coupon",
"create_coupon",
"update_coupon",
"delete_coupon",
// Order notes
"get_order_notes",
"get_order_note",
"create_order_note",
"delete_order_note",
// Order refunds
"get_order_refunds",
"get_order_refund",
"create_order_refund",
"delete_order_refund",
// Product variations
"get_product_variations",
"get_product_variation",
"create_product_variation",
"update_product_variation",
"delete_product_variation",
// Product attributes
"get_product_attributes",
"get_product_attribute",
"create_product_attribute",
"update_product_attribute",
"delete_product_attribute",
// Product attribute terms
"get_attribute_terms",
"get_attribute_term",
"create_attribute_term",
"update_attribute_term",
"delete_attribute_term",
// Product categories
"get_product_categories",
"get_product_category",
"create_product_category",
"update_product_category",
"delete_product_category",
// Product tags
"get_product_tags",
"get_product_tag",
"create_product_tag",
"update_product_tag",
"delete_product_tag",
// Product reviews
"get_product_reviews",
"get_product_review",
"create_product_review",
"update_product_review",
"delete_product_review",
// Payment gateways
"get_payment_gateways",
"get_payment_gateway",
"update_payment_gateway",
// Settings
"get_settings",
"get_setting_options",
"update_setting_option",
// System status
"get_system_status",
"get_system_status_tools",
"run_system_status_tool",
// Data
"get_data",
"get_continents",
"get_countries",
"get_currencies",
"get_current_currency",
// Meta data operations for products
"get_product_meta",
"update_product_meta",
"create_product_meta",
"delete_product_meta",
// Meta data operations for orders
"get_order_meta",
"update_order_meta",
"create_order_meta",
"delete_order_meta",
// Meta data operations for customers
"get_customer_meta",
"update_customer_meta",
"create_customer_meta",
"delete_customer_meta",
];
// Create WordPress REST API client
let client;
if (wpMethods.includes(method)) {
if (!username || !password) {
throw new Error(
"WordPress credentials not provided in environment variables or request parameters"
);
}
const auth = Buffer.from(`${username}:${password}`).toString("base64");
client = axios.create({
baseURL: `${siteUrl}/wp-json/wp/v2`,
headers: {
Authorization: `Basic ${auth}`,
"Content-Type": "application/json",
},
});
} else if (wooMethods.includes(method)) {
// For WooCommerce API requests
if (!consumerKey || !consumerSecret) {
throw new Error(
"WooCommerce API credentials not provided in environment variables or request parameters"
);
}
client = axios.create({
baseURL: `${siteUrl}/wp-json/wc/v3`,
params: {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
},
headers: {
"Content-Type": "application/json",
},
});
} else {
throw new Error(`Unknown method: ${method}`);
}
// Handle WordPress API methods
switch (method) {
case "create_post":
if (!params.title || !params.content) {
throw new Error("Title and content are required for creating a post");
}
const createResponse = await client.post("/posts", {
title: params.title,
content: params.content,
status: params.status || "draft",
});
return createResponse.data;
case "get_posts":
const getResponse = await client.get("/posts", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
},
});
return getResponse.data;
case "update_post":
if (!params.postId) {
throw new Error("Post ID is required for updating a post");
}
const updateData: Record<string, any> = {};
if (params.title) updateData.title = params.title;
if (params.content) updateData.content = params.content;
if (params.status) updateData.status = params.status;
const updateResponse = await client.post(
`/posts/${params.postId}`,
updateData
);
return updateResponse.data;
// Handle WooCommerce API methods
// Products
case "get_products":
const productsResponse = await client.get("/products", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return productsResponse.data;
case "get_product":
if (!params.productId) {
throw new Error("Product ID is required");
}
const productResponse = await client.get(
`/products/${params.productId}`
);
return productResponse.data;
case "create_product":
if (!params.productData) {
throw new Error("Product data is required for creating a product");
}
const createProductResponse = await client.post(
"/products",
params.productData
);
return createProductResponse.data;
case "update_product":
if (!params.productId) {
throw new Error("Product ID is required for updating a product");
}
if (!params.productData) {
throw new Error("Product data is required for updating a product");
}
const updateProductResponse = await client.put(
`/products/${params.productId}`,
params.productData
);
return updateProductResponse.data;
case "delete_product":
if (!params.productId) {
throw new Error("Product ID is required for deleting a product");
}
const deleteProductResponse = await client.delete(
`/products/${params.productId}`,
{
params: {
force: params.force || false,
},
}
);
return deleteProductResponse.data;
// Orders
case "get_orders":
const ordersResponse = await client.get("/orders", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return ordersResponse.data;
case "get_order":
if (!params.orderId) {
throw new Error("Order ID is required");
}
const orderResponse = await client.get(`/orders/${params.orderId}`);
return orderResponse.data;
case "create_order":
if (!params.orderData) {
throw new Error("Order data is required for creating an order");
}
const createOrderResponse = await client.post(
"/orders",
params.orderData
);
return createOrderResponse.data;
case "update_order":
if (!params.orderId) {
throw new Error("Order ID is required for updating an order");
}
if (!params.orderData) {
throw new Error("Order data is required for updating an order");
}
const updateOrderResponse = await client.put(
`/orders/${params.orderId}`,
params.orderData
);
return updateOrderResponse.data;
case "delete_order":
if (!params.orderId) {
throw new Error("Order ID is required for deleting an order");
}
const deleteOrderResponse = await client.delete(
`/orders/${params.orderId}`,
{
params: {
force: params.force || false,
},
}
);
return deleteOrderResponse.data;
// Customers
case "get_customers":
const customersResponse = await client.get("/customers", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return customersResponse.data;
case "get_customer":
if (!params.customerId) {
throw new Error("Customer ID is required");
}
const customerResponse = await client.get(
`/customers/${params.customerId}`
);
return customerResponse.data;
case "create_customer":
if (!params.customerData) {
throw new Error("Customer data is required for creating a customer");
}
const createCustomerResponse = await client.post(
"/customers",
params.customerData
);
return createCustomerResponse.data;
case "update_customer":
if (!params.customerId) {
throw new Error("Customer ID is required for updating a customer");
}
if (!params.customerData) {
throw new Error("Customer data is required for updating a customer");
}
const updateCustomerResponse = await client.put(
`/customers/${params.customerId}`,
params.customerData
);
return updateCustomerResponse.data;
case "delete_customer":
if (!params.customerId) {
throw new Error("Customer ID is required for deleting a customer");
}
const deleteCustomerResponse = await client.delete(
`/customers/${params.customerId}`,
{
params: {
force: params.force || false,
},
}
);
return deleteCustomerResponse.data;
// Reports
case "get_sales_report":
const salesReportResponse = await client.get("/reports/sales", {
params: {
period: params.period || "month",
date_min: params.dateMin || "",
date_max: params.dateMax || "",
...params.filters,
},
});
return salesReportResponse.data;
case "get_products_report":
const productsReportResponse = await client.get("/reports/products", {
params: {
period: params.period || "month",
date_min: params.dateMin || "",
date_max: params.dateMax || "",
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return productsReportResponse.data;
case "get_orders_report":
const ordersReportResponse = await client.get("/reports/orders", {
params: {
period: params.period || "month",
date_min: params.dateMin || "",
date_max: params.dateMax || "",
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return ordersReportResponse.data;
case "get_categories_report":
const categoriesReportResponse = await client.get(
"/reports/categories",
{
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
}
);
return categoriesReportResponse.data;
case "get_customers_report":
const customersReportResponse = await client.get("/reports/customers", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return customersReportResponse.data;
case "get_stock_report":
const stockReportResponse = await client.get("/reports/stock", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return stockReportResponse.data;
case "get_coupons_report":
const couponsReportResponse = await client.get("/reports/coupons", {
params: {
period: params.period || "month",
date_min: params.dateMin || "",
date_max: params.dateMax || "",
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return couponsReportResponse.data;
case "get_taxes_report":
const taxesReportResponse = await client.get("/reports/taxes", {
params: {
period: params.period || "month",
date_min: params.dateMin || "",
date_max: params.dateMax || "",
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return taxesReportResponse.data;
// Shipping Zones
case "get_shipping_zones":
const shippingZonesResponse = await client.get("/shipping/zones", {
params: {
...params.filters,
},
});
return shippingZonesResponse.data;
case "get_shipping_zone":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
const shippingZoneResponse = await client.get(
`/shipping/zones/${params.zoneId}`
);
return shippingZoneResponse.data;
case "create_shipping_zone":
if (!params.zoneData) {
throw new Error("Zone data is required for creating a shipping zone");
}
const createShippingZoneResponse = await client.post(
"/shipping/zones",
params.zoneData
);
return createShippingZoneResponse.data;
case "update_shipping_zone":
if (!params.zoneId) {
throw new Error("Zone ID is required for updating a shipping zone");
}
if (!params.zoneData) {
throw new Error("Zone data is required for updating a shipping zone");
}
const updateShippingZoneResponse = await client.put(
`/shipping/zones/${params.zoneId}`,
params.zoneData
);
return updateShippingZoneResponse.data;
case "delete_shipping_zone":
if (!params.zoneId) {
throw new Error("Zone ID is required for deleting a shipping zone");
}
const deleteShippingZoneResponse = await client.delete(
`/shipping/zones/${params.zoneId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteShippingZoneResponse.data;
// Shipping Methods
case "get_shipping_methods":
const shippingMethodsResponse = await client.get("/shipping_methods");
return shippingMethodsResponse.data;
case "get_shipping_zone_methods":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
const zoneMethodsResponse = await client.get(
`/shipping/zones/${params.zoneId}/methods`
);
return zoneMethodsResponse.data;
case "create_shipping_zone_method":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
if (!params.methodData) {
throw new Error(
"Method data is required for creating a shipping method"
);
}
const createMethodResponse = await client.post(
`/shipping/zones/${params.zoneId}/methods`,
params.methodData
);
return createMethodResponse.data;
case "update_shipping_zone_method":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
if (!params.instanceId) {
throw new Error("Method instance ID is required");
}
if (!params.methodData) {
throw new Error(
"Method data is required for updating a shipping method"
);
}
const updateMethodResponse = await client.put(
`/shipping/zones/${params.zoneId}/methods/${params.instanceId}`,
params.methodData
);
return updateMethodResponse.data;
case "delete_shipping_zone_method":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
if (!params.instanceId) {
throw new Error("Method instance ID is required");
}
const deleteMethodResponse = await client.delete(
`/shipping/zones/${params.zoneId}/methods/${params.instanceId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteMethodResponse.data;
// Shipping Zone Locations
case "get_shipping_zone_locations":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
const locationsResponse = await client.get(
`/shipping/zones/${params.zoneId}/locations`
);
return locationsResponse.data;
case "update_shipping_zone_locations":
if (!params.zoneId) {
throw new Error("Zone ID is required");
}
if (!params.locations) {
throw new Error("Locations data is required");
}
const updateLocationsResponse = await client.put(
`/shipping/zones/${params.zoneId}/locations`,
params.locations
);
return updateLocationsResponse.data;
// Tax Classes
case "get_tax_classes":
const taxClassesResponse = await client.get("/taxes/classes");
return taxClassesResponse.data;
case "create_tax_class":
if (!params.taxClassData) {
throw new Error("Tax class data is required");
}
const createTaxClassResponse = await client.post(
"/taxes/classes",
params.taxClassData
);
return createTaxClassResponse.data;
case "delete_tax_class":
if (!params.slug) {
throw new Error("Tax class slug is required");
}
const deleteTaxClassResponse = await client.delete(
`/taxes/classes/${params.slug}`,
{
params: {
force: params.force || true,
},
}
);
return deleteTaxClassResponse.data;
// Tax Rates
case "get_tax_rates":
const taxRatesResponse = await client.get("/taxes", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return taxRatesResponse.data;
case "get_tax_rate":
if (!params.rateId) {
throw new Error("Tax rate ID is required");
}
const taxRateResponse = await client.get(`/taxes/${params.rateId}`);
return taxRateResponse.data;
case "create_tax_rate":
if (!params.taxRateData) {
throw new Error("Tax rate data is required");
}
const createTaxRateResponse = await client.post(
"/taxes",
params.taxRateData
);
return createTaxRateResponse.data;
case "update_tax_rate":
if (!params.rateId) {
throw new Error("Tax rate ID is required");
}
if (!params.taxRateData) {
throw new Error("Tax rate data is required");
}
const updateTaxRateResponse = await client.put(
`/taxes/${params.rateId}`,
params.taxRateData
);
return updateTaxRateResponse.data;
case "delete_tax_rate":
if (!params.rateId) {
throw new Error("Tax rate ID is required");
}
const deleteTaxRateResponse = await client.delete(
`/taxes/${params.rateId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteTaxRateResponse.data;
// Coupons
case "get_coupons":
const couponsResponse = await client.get("/coupons", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return couponsResponse.data;
case "get_coupon":
if (!params.couponId) {
throw new Error("Coupon ID is required");
}
const couponResponse = await client.get(`/coupons/${params.couponId}`);
return couponResponse.data;
case "create_coupon":
if (!params.couponData) {
throw new Error("Coupon data is required");
}
const createCouponResponse = await client.post(
"/coupons",
params.couponData
);
return createCouponResponse.data;
case "update_coupon":
if (!params.couponId) {
throw new Error("Coupon ID is required");
}
if (!params.couponData) {
throw new Error("Coupon data is required");
}
const updateCouponResponse = await client.put(
`/coupons/${params.couponId}`,
params.couponData
);
return updateCouponResponse.data;
case "delete_coupon":
if (!params.couponId) {
throw new Error("Coupon ID is required");
}
const deleteCouponResponse = await client.delete(
`/coupons/${params.couponId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteCouponResponse.data;
// Order Notes
case "get_order_notes":
if (!params.orderId) {
throw new Error("Order ID is required");
}
const orderNotesResponse = await client.get(
`/orders/${params.orderId}/notes`,
{
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
}
);
return orderNotesResponse.data;
case "get_order_note":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.noteId) {
throw new Error("Note ID is required");
}
const orderNoteResponse = await client.get(
`/orders/${params.orderId}/notes/${params.noteId}`
);
return orderNoteResponse.data;
case "create_order_note":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.noteData) {
throw new Error("Note data is required");
}
const createOrderNoteResponse = await client.post(
`/orders/${params.orderId}/notes`,
params.noteData
);
return createOrderNoteResponse.data;
case "delete_order_note":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.noteId) {
throw new Error("Note ID is required");
}
const deleteOrderNoteResponse = await client.delete(
`/orders/${params.orderId}/notes/${params.noteId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteOrderNoteResponse.data;
// Order Refunds
case "get_order_refunds":
if (!params.orderId) {
throw new Error("Order ID is required");
}
const refundsResponse = await client.get(
`/orders/${params.orderId}/refunds`,
{
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
}
);
return refundsResponse.data;
case "get_order_refund":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.refundId) {
throw new Error("Refund ID is required");
}
const refundResponse = await client.get(
`/orders/${params.orderId}/refunds/${params.refundId}`
);
return refundResponse.data;
case "create_order_refund":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.refundData) {
throw new Error("Refund data is required");
}
const createRefundResponse = await client.post(
`/orders/${params.orderId}/refunds`,
params.refundData
);
return createRefundResponse.data;
case "delete_order_refund":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.refundId) {
throw new Error("Refund ID is required");
}
const deleteRefundResponse = await client.delete(
`/orders/${params.orderId}/refunds/${params.refundId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteRefundResponse.data;
// Product Variations
case "get_product_variations":
if (!params.productId) {
throw new Error("Product ID is required");
}
const variationsResponse = await client.get(
`/products/${params.productId}/variations`,
{
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
}
);
return variationsResponse.data;
case "get_product_variation":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.variationId) {
throw new Error("Variation ID is required");
}
const variationResponse = await client.get(
`/products/${params.productId}/variations/${params.variationId}`
);
return variationResponse.data;
case "create_product_variation":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.variationData) {
throw new Error("Variation data is required");
}
const createVariationResponse = await client.post(
`/products/${params.productId}/variations`,
params.variationData
);
return createVariationResponse.data;
case "update_product_variation":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.variationId) {
throw new Error("Variation ID is required");
}
if (!params.variationData) {
throw new Error("Variation data is required");
}
const updateVariationResponse = await client.put(
`/products/${params.productId}/variations/${params.variationId}`,
params.variationData
);
return updateVariationResponse.data;
case "delete_product_variation":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.variationId) {
throw new Error("Variation ID is required");
}
const deleteVariationResponse = await client.delete(
`/products/${params.productId}/variations/${params.variationId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteVariationResponse.data;
// Product Attributes
case "get_product_attributes":
const attributesResponse = await client.get("/products/attributes", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return attributesResponse.data;
case "get_product_attribute":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
const attributeResponse = await client.get(
`/products/attributes/${params.attributeId}`
);
return attributeResponse.data;
case "create_product_attribute":
if (!params.attributeData) {
throw new Error("Attribute data is required");
}
const createAttributeResponse = await client.post(
"/products/attributes",
params.attributeData
);
return createAttributeResponse.data;
case "update_product_attribute":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
if (!params.attributeData) {
throw new Error("Attribute data is required");
}
const updateAttributeResponse = await client.put(
`/products/attributes/${params.attributeId}`,
params.attributeData
);
return updateAttributeResponse.data;
case "delete_product_attribute":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
const deleteAttributeResponse = await client.delete(
`/products/attributes/${params.attributeId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteAttributeResponse.data;
// Product Attribute Terms
case "get_attribute_terms":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
const termsResponse = await client.get(
`/products/attributes/${params.attributeId}/terms`,
{
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
}
);
return termsResponse.data;
case "get_attribute_term":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
if (!params.termId) {
throw new Error("Term ID is required");
}
const termResponse = await client.get(
`/products/attributes/${params.attributeId}/terms/${params.termId}`
);
return termResponse.data;
case "create_attribute_term":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
if (!params.termData) {
throw new Error("Term data is required");
}
const createTermResponse = await client.post(
`/products/attributes/${params.attributeId}/terms`,
params.termData
);
return createTermResponse.data;
case "update_attribute_term":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
if (!params.termId) {
throw new Error("Term ID is required");
}
if (!params.termData) {
throw new Error("Term data is required");
}
const updateTermResponse = await client.put(
`/products/attributes/${params.attributeId}/terms/${params.termId}`,
params.termData
);
return updateTermResponse.data;
case "delete_attribute_term":
if (!params.attributeId) {
throw new Error("Attribute ID is required");
}
if (!params.termId) {
throw new Error("Term ID is required");
}
const deleteTermResponse = await client.delete(
`/products/attributes/${params.attributeId}/terms/${params.termId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteTermResponse.data;
// Product Categories
case "get_product_categories":
const categoriesResponse = await client.get("/products/categories", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return categoriesResponse.data;
case "get_product_category":
if (!params.categoryId) {
throw new Error("Category ID is required");
}
const categoryResponse = await client.get(
`/products/categories/${params.categoryId}`
);
return categoryResponse.data;
case "create_product_category":
if (!params.categoryData) {
throw new Error("Category data is required");
}
const createCategoryResponse = await client.post(
"/products/categories",
params.categoryData
);
return createCategoryResponse.data;
case "update_product_category":
if (!params.categoryId) {
throw new Error("Category ID is required");
}
if (!params.categoryData) {
throw new Error("Category data is required");
}
const updateCategoryResponse = await client.put(
`/products/categories/${params.categoryId}`,
params.categoryData
);
return updateCategoryResponse.data;
case "delete_product_category":
if (!params.categoryId) {
throw new Error("Category ID is required");
}
const deleteCategoryResponse = await client.delete(
`/products/categories/${params.categoryId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteCategoryResponse.data;
// Product Tags
case "get_product_tags":
const tagsResponse = await client.get("/products/tags", {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return tagsResponse.data;
case "get_product_tag":
if (!params.tagId) {
throw new Error("Tag ID is required");
}
const tagResponse = await client.get(`/products/tags/${params.tagId}`);
return tagResponse.data;
case "create_product_tag":
if (!params.tagData) {
throw new Error("Tag data is required");
}
const createTagResponse = await client.post(
"/products/tags",
params.tagData
);
return createTagResponse.data;
case "update_product_tag":
if (!params.tagId) {
throw new Error("Tag ID is required");
}
if (!params.tagData) {
throw new Error("Tag data is required");
}
const updateTagResponse = await client.put(
`/products/tags/${params.tagId}`,
params.tagData
);
return updateTagResponse.data;
case "delete_product_tag":
if (!params.tagId) {
throw new Error("Tag ID is required");
}
const deleteTagResponse = await client.delete(
`/products/tags/${params.tagId}`,
{
params: {
force: params.force || true,
},
}
);
return deleteTagResponse.data;
// Product Reviews
case "get_product_reviews":
const reviewsParams = params.productId
? `/products/${params.productId}/reviews`
: "/products/reviews";
const reviewsResponse = await client.get(reviewsParams, {
params: {
per_page: params.perPage || 10,
page: params.page || 1,
...params.filters,
},
});
return reviewsResponse.data;
case "get_product_review":
if (!params.reviewId) {
throw new Error("Review ID is required");
}
const reviewParams = params.productId
? `/products/${params.productId}/reviews/${params.reviewId}`
: `/products/reviews/${params.reviewId}`;
const reviewResponse = await client.get(reviewParams);
return reviewResponse.data;
case "create_product_review":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.reviewData) {
throw new Error("Review data is required");
}
const createReviewResponse = await client.post(
`/products/${params.productId}/reviews`,
params.reviewData
);
return createReviewResponse.data;
case "update_product_review":
if (!params.reviewId) {
throw new Error("Review ID is required");
}
if (!params.reviewData) {
throw new Error("Review data is required");
}
const reviewPath = params.productId
? `/products/${params.productId}/reviews/${params.reviewId}`
: `/products/reviews/${params.reviewId}`;
const updateReviewResponse = await client.put(
reviewPath,
params.reviewData
);
return updateReviewResponse.data;
case "delete_product_review":
if (!params.reviewId) {
throw new Error("Review ID is required");
}
const deletePath = params.productId
? `/products/${params.productId}/reviews/${params.reviewId}`
: `/products/reviews/${params.reviewId}`;
const deleteReviewResponse = await client.delete(deletePath, {
params: {
force: params.force || true,
},
});
return deleteReviewResponse.data;
// Payment Gateways
case "get_payment_gateways":
const gatewaysResponse = await client.get("/payment_gateways");
return gatewaysResponse.data;
case "get_payment_gateway":
if (!params.gatewayId) {
throw new Error("Gateway ID is required");
}
const gatewayResponse = await client.get(
`/payment_gateways/${params.gatewayId}`
);
return gatewayResponse.data;
case "update_payment_gateway":
if (!params.gatewayId) {
throw new Error("Gateway ID is required");
}
if (!params.gatewayData) {
throw new Error("Gateway data is required");
}
const updateGatewayResponse = await client.put(
`/payment_gateways/${params.gatewayId}`,
params.gatewayData
);
return updateGatewayResponse.data;
// Settings
case "get_settings":
const settingsResponse = await client.get("/settings");
return settingsResponse.data;
case "get_setting_options":
if (!params.group) {
throw new Error("Settings group is required");
}
const settingOptionsResponse = await client.get(
`/settings/${params.group}`
);
return settingOptionsResponse.data;
case "update_setting_option":
if (!params.group) {
throw new Error("Settings group is required");
}
if (!params.id) {
throw new Error("Setting ID is required");
}
if (!params.settingData) {
throw new Error("Setting data is required");
}
const updateSettingResponse = await client.put(
`/settings/${params.group}/${params.id}`,
params.settingData
);
return updateSettingResponse.data;
// System Status
case "get_system_status":
const statusResponse = await client.get("/system_status");
return statusResponse.data;
case "get_system_status_tools":
const toolsResponse = await client.get("/system_status/tools");
return toolsResponse.data;
case "run_system_status_tool":
if (!params.toolId) {
throw new Error("Tool ID is required");
}
const runToolResponse = await client.put(
`/system_status/tools/${params.toolId}`
);
return runToolResponse.data;
// Data
case "get_data":
const dataResponse = await client.get("/data");
return dataResponse.data;
case "get_continents":
const continentsResponse = await client.get("/data/continents");
return continentsResponse.data;
case "get_countries":
const countriesResponse = await client.get("/data/countries");
return countriesResponse.data;
case "get_currencies":
const currenciesResponse = await client.get("/data/currencies");
return currenciesResponse.data;
case "get_current_currency":
const currentCurrencyResponse = await client.get(
"/data/currencies/current"
);
return currentCurrencyResponse.data;
// Meta operations for WordPress posts
case "get_post_meta":
if (!params.postId) {
throw new Error("Post ID is required");
}
// Get all meta or a specific meta key
let metaEndpoint = params.metaKey
? `/posts/${params.postId}/meta/${params.metaKey}`
: `/posts/${params.postId}/meta`;
const getPostMetaResponse = await client.get(metaEndpoint);
return getPostMetaResponse.data;
case "create_post_meta":
if (!params.postId) {
throw new Error("Post ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
if (params.metaValue === undefined) {
throw new Error("Meta value is required");
}
const createPostMetaResponse = await client.post(
`/posts/${params.postId}/meta`,
{
key: params.metaKey,
value: params.metaValue,
}
);
return createPostMetaResponse.data;
case "update_post_meta":
if (!params.postId) {
throw new Error("Post ID is required");
}
if (!params.metaId) {
throw new Error("Meta ID is required");
}
if (params.metaValue === undefined) {
throw new Error("Meta value is required");
}
const updatePostMetaResponse = await client.put(
`/posts/${params.postId}/meta/${params.metaId}`,
{
value: params.metaValue,
}
);
return updatePostMetaResponse.data;
case "delete_post_meta":
if (!params.postId) {
throw new Error("Post ID is required");
}
if (!params.metaId) {
throw new Error("Meta ID is required");
}
const deletePostMetaResponse = await client.delete(
`/posts/${params.postId}/meta/${params.metaId}`,
{
params: {
force: params.force || true,
},
}
);
return deletePostMetaResponse.data;
// Meta operations for WooCommerce products
case "get_product_meta":
if (!params.productId) {
throw new Error("Product ID is required");
}
const getProductResponse = await client.get(
`/products/${params.productId}`
);
// WooCommerce keeps meta in the meta_data array
const productMetaData = getProductResponse.data.meta_data || [];
// If a specific key is requested, filter the meta data
if (params.metaKey) {
return productMetaData.filter(
(meta: WooMetaData) => meta.key === params.metaKey
);
}
return productMetaData;
case "create_product_meta":
case "update_product_meta":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
if (params.metaValue === undefined) {
throw new Error("Meta value is required");
}
// First get the product to see if the meta key exists
const productMetaResponse = await client.get(
`/products/${params.productId}`
);
let product = productMetaResponse.data;
let metaData: WooMetaData[] = product.meta_data || [];
// Look for existing meta with the same key
const existingMetaIndex = metaData.findIndex(
(meta: WooMetaData) => meta.key === params.metaKey
);
if (existingMetaIndex >= 0) {
// Update existing meta
metaData[existingMetaIndex].value = params.metaValue;
} else {
// Add new meta
metaData.push({
key: params.metaKey,
value: params.metaValue,
});
}
// Update the product with the modified meta_data
const updateProductMetaResponse = await client.put(
`/products/${params.productId}`,
{
meta_data: metaData,
}
);
return updateProductMetaResponse.data.meta_data;
case "delete_product_meta":
if (!params.productId) {
throw new Error("Product ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
// First get the product to see if the meta key exists
const getProductForDeleteResponse = await client.get(
`/products/${params.productId}`
);
let productForDelete = getProductForDeleteResponse.data;
let currentMetaData: WooMetaData[] = productForDelete.meta_data || [];
// Filter out the meta key to delete
const updatedMetaData = currentMetaData.filter(
(meta: WooMetaData) => meta.key !== params.metaKey
);
// Update the product with the filtered meta_data
const deleteProductMetaResponse = await client.put(
`/products/${params.productId}`,
{
meta_data: updatedMetaData,
}
);
return deleteProductMetaResponse.data.meta_data;
// Meta operations for WooCommerce orders
case "get_order_meta":
if (!params.orderId) {
throw new Error("Order ID is required");
}
const getOrderResponse = await client.get(`/orders/${params.orderId}`);
// WooCommerce keeps meta in the meta_data array
const orderMetaData = getOrderResponse.data.meta_data || [];
// If a specific key is requested, filter the meta data
if (params.metaKey) {
return orderMetaData.filter(
(meta: WooMetaData) => meta.key === params.metaKey
);
}
return orderMetaData;
case "create_order_meta":
case "update_order_meta":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
if (params.metaValue === undefined) {
throw new Error("Meta value is required");
}
// First get the order to see if the meta key exists
const orderMetaResponse = await client.get(`/orders/${params.orderId}`);
let order = orderMetaResponse.data;
let orderMeta: WooMetaData[] = order.meta_data || [];
// Look for existing meta with the same key
const existingOrderMetaIndex = orderMeta.findIndex(
(meta: WooMetaData) => meta.key === params.metaKey
);
if (existingOrderMetaIndex >= 0) {
// Update existing meta
orderMeta[existingOrderMetaIndex].value = params.metaValue;
} else {
// Add new meta
orderMeta.push({
key: params.metaKey,
value: params.metaValue,
});
}
// Update the order with the modified meta_data
const updateOrderMetaResponse = await client.put(
`/orders/${params.orderId}`,
{
meta_data: orderMeta,
}
);
return updateOrderMetaResponse.data.meta_data;
case "delete_order_meta":
if (!params.orderId) {
throw new Error("Order ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
// First get the order to see if the meta key exists
const getOrderForDeleteResponse = await client.get(
`/orders/${params.orderId}`
);
let orderForDelete = getOrderForDeleteResponse.data;
let currentOrderMeta: WooMetaData[] = orderForDelete.meta_data || [];
// Filter out the meta key to delete
const updatedOrderMeta = currentOrderMeta.filter(
(meta: WooMetaData) => meta.key !== params.metaKey
);
// Update the order with the filtered meta_data
const deleteOrderMetaResponse = await client.put(
`/orders/${params.orderId}`,
{
meta_data: updatedOrderMeta,
}
);
return deleteOrderMetaResponse.data.meta_data;
// Meta operations for WooCommerce customers
case "get_customer_meta":
if (!params.customerId) {
throw new Error("Customer ID is required");
}
const getCustomerResponse = await client.get(
`/customers/${params.customerId}`
);
// WooCommerce keeps meta in the meta_data array
const customerMetaData = getCustomerResponse.data.meta_data || [];
// If a specific key is requested, filter the meta data
if (params.metaKey) {
return customerMetaData.filter(
(meta: WooMetaData) => meta.key === params.metaKey
);
}
return customerMetaData;
case "create_customer_meta":
case "update_customer_meta":
if (!params.customerId) {
throw new Error("Customer ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
if (params.metaValue === undefined) {
throw new Error("Meta value is required");
}
// First get the customer to see if the meta key exists
const customerMetaResponse = await client.get(
`/customers/${params.customerId}`
);
let customer = customerMetaResponse.data;
let customerMeta: WooMetaData[] = customer.meta_data || [];
// Look for existing meta with the same key
const existingCustomerMetaIndex = customerMeta.findIndex(
(meta: WooMetaData) => meta.key === params.metaKey
);
if (existingCustomerMetaIndex >= 0) {
// Update existing meta
customerMeta[existingCustomerMetaIndex].value = params.metaValue;
} else {
// Add new meta
customerMeta.push({
key: params.metaKey,
value: params.metaValue,
});
}
// Update the customer with the modified meta_data
const updateCustomerMetaResponse = await client.put(
`/customers/${params.customerId}`,
{
meta_data: customerMeta,
}
);
return updateCustomerMetaResponse.data.meta_data;
case "delete_customer_meta":
if (!params.customerId) {
throw new Error("Customer ID is required");
}
if (!params.metaKey) {
throw new Error("Meta key is required");
}
// First get the customer to see if the meta key exists
const getCustomerForDeleteResponse = await client.get(
`/customers/${params.customerId}`
);
let customerForDelete = getCustomerForDeleteResponse.data;
let currentCustomerMeta: WooMetaData[] =
customerForDelete.meta_data || [];
// Filter out the meta key to delete
const updatedCustomerMeta = currentCustomerMeta.filter(
(meta: WooMetaData) => meta.key !== params.metaKey
);
// Update the customer with the filtered meta_data
const deleteCustomerMetaResponse = await client.put(
`/customers/${params.customerId}`,
{
meta_data: updatedCustomerMeta,
}
);
return deleteCustomerMetaResponse.data.meta_data;
default:
throw new Error(`Unknown method: ${method}`);
}
} catch (error: unknown) {
if (isAxiosError(error)) {
throw new Error(
`API error: ${error.response?.data?.message || error.message}`
);
}
throw error;
}
}
const rl = createInterface({
input: process.stdin,
output: process.stdout,
terminal: false,
});
rl.on("line", async (line) => {
let request: JsonRpcRequest;
try {
request = JSON.parse(line);
if (request.jsonrpc !== "2.0") {
throw new Error("Invalid JSON-RPC version");
}
} catch (error) {
console.log(
JSON.stringify({
jsonrpc: "2.0",
id: null,
error: {
code: -32700,
message: "Parse error",
data: error instanceof Error ? error.message : String(error),
},
})
);
return;
}
try {
const result = await handleWooCommerceRequest(
request.method,
request.params
);
console.log(
JSON.stringify({
jsonrpc: "2.0",
id: request.id,
result,
})
);
} catch (error) {
console.log(
JSON.stringify({
jsonrpc: "2.0",
id: request.id,
error: {
code: -32000,
message: error instanceof Error ? error.message : String(error),
},
})
);
}
});
process.on("SIGINT", () => {
rl.close();
process.exit(0);
});
console.error("WooCommerce MCP server running on stdin/stdout");