WooCommerce MCP Server

  • src
#!/usr/bin/env node import axios from 'axios'; import { createInterface } from 'readline'; 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 => 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 = product.meta_data || []; // Look for existing meta with the same key const existingMetaIndex = metaData.findIndex(meta => 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 = productForDelete.meta_data || []; // Filter out the meta key to delete const updatedMetaData = currentMetaData.filter(meta => 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 => 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 = order.meta_data || []; // Look for existing meta with the same key const existingOrderMetaIndex = orderMeta.findIndex(meta => 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 = orderForDelete.meta_data || []; // Filter out the meta key to delete const updatedOrderMeta = currentOrderMeta.filter(meta => 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 => 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 = customer.meta_data || []; // Look for existing meta with the same key const existingCustomerMetaIndex = customerMeta.findIndex(meta => 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 = customerForDelete.meta_data || []; // Filter out the meta key to delete const updatedCustomerMeta = currentCustomerMeta.filter(meta => 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');