Skip to main content
Glama
index.ts27.7 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode, } from "@modelcontextprotocol/sdk/types.js"; import axios from "axios"; import { WooMetaData } from "./types.js"; // Get WordPress credentials from environment variables const SITE_URL = process.env.WORDPRESS_SITE_URL || ""; const USERNAME = process.env.WORDPRESS_USERNAME || ""; const PASSWORD = process.env.WORDPRESS_PASSWORD || ""; const CONSUMER_KEY = process.env.WOOCOMMERCE_CONSUMER_KEY || ""; const CONSUMER_SECRET = process.env.WOOCOMMERCE_CONSUMER_SECRET || ""; 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 ); }; // Helper function to make authenticated WooCommerce API requests async function makeWooCommerceRequest( endpoint: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET', data?: any ): Promise<any> { if (!SITE_URL || !CONSUMER_KEY || !CONSUMER_SECRET) { throw new McpError( ErrorCode.InvalidRequest, "WooCommerce credentials not configured. Please set WORDPRESS_SITE_URL, WOOCOMMERCE_CONSUMER_KEY, and WOOCOMMERCE_CONSUMER_SECRET environment variables." ); } const url = `${SITE_URL}/wp-json/wc/v3/${endpoint}`; try { const response = await axios({ method, url, data, auth: { username: CONSUMER_KEY, password: CONSUMER_SECRET, }, headers: { 'Content-Type': 'application/json', }, }); return response.data; } catch (error) { if (isAxiosError(error)) { const errorMessage = error.response?.data?.message || error.message; throw new McpError(ErrorCode.InternalError, `WooCommerce API error: ${errorMessage}`); } throw new McpError(ErrorCode.InternalError, `Request failed: ${String(error)}`); } } // Helper function to make WordPress REST API requests async function makeWordPressRequest( endpoint: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET', data?: any ): Promise<any> { if (!SITE_URL || !USERNAME || !PASSWORD) { throw new McpError( ErrorCode.InvalidRequest, "WordPress credentials not configured. Please set WORDPRESS_SITE_URL, WORDPRESS_USERNAME, and WORDPRESS_PASSWORD environment variables." ); } const url = `${SITE_URL}/wp-json/wp/v2/${endpoint}`; try { const response = await axios({ method, url, data, auth: { username: USERNAME, password: PASSWORD, }, headers: { 'Content-Type': 'application/json', }, }); return response.data; } catch (error) { if (isAxiosError(error)) { const errorMessage = error.response?.data?.message || error.message; throw new McpError(ErrorCode.InternalError, `WordPress API error: ${errorMessage}`); } throw new McpError(ErrorCode.InternalError, `Request failed: ${String(error)}`); } } // Create the MCP server const server = new Server( { name: "woocommerce-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_mcp_config", description: "Generate MCP server configuration for this WooCommerce server", inputSchema: { type: "object", properties: { useEnvFile: { type: "boolean", description: "Whether to use .env file for credentials (recommended)" }, serverName: { type: "string", description: "Name for the MCP server (default: woocommerce)" } }, }, }, { name: "get_products", description: "Get a list of WooCommerce products", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of products per page (default: 10)" }, page: { type: "number", description: "Page number (default: 1)" }, filters: { type: "object", description: "Additional filters for products" } }, }, }, { name: "get_product", description: "Get a specific WooCommerce product by ID", inputSchema: { type: "object", properties: { productId: { type: "string", description: "Product ID" } }, required: ["productId"], }, }, { name: "create_product", description: "Create a new WooCommerce product", inputSchema: { type: "object", properties: { productData: { type: "object", description: "Product data object" } }, required: ["productData"], }, }, { name: "update_product", description: "Update an existing WooCommerce product", inputSchema: { type: "object", properties: { productId: { type: "string", description: "Product ID" }, productData: { type: "object", description: "Product data to update" } }, required: ["productId", "productData"], }, }, { name: "delete_product", description: "Delete a WooCommerce product", inputSchema: { type: "object", properties: { productId: { type: "string", description: "Product ID" }, force: { type: "boolean", description: "Force delete (bypass trash)" } }, required: ["productId"], }, }, { name: "get_product_categories", description: "Get WooCommerce product categories", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of categories per page" }, page: { type: "number", description: "Page number" }, filters: { type: "object", description: "Additional filters" } }, }, }, { name: "create_product_category", description: "Create a new product category", inputSchema: { type: "object", properties: { categoryData: { type: "object", description: "Category data" } }, required: ["categoryData"], }, }, { name: "get_orders", description: "Get WooCommerce orders", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of orders per page" }, page: { type: "number", description: "Page number" }, filters: { type: "object", description: "Additional filters" } }, }, }, { name: "get_order", description: "Get a specific order by ID", inputSchema: { type: "object", properties: { orderId: { type: "string", description: "Order ID" } }, required: ["orderId"], }, }, { name: "get_customers", description: "Get WooCommerce customers", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of customers per page" }, page: { type: "number", description: "Page number" }, filters: { type: "object", description: "Additional filters" } }, }, }, { name: "create_customer", description: "Create a new customer", inputSchema: { type: "object", properties: { customerData: { type: "object", description: "Customer data" } }, required: ["customerData"], }, }, { name: "get_sales_report", description: "Get WooCommerce sales report", inputSchema: { type: "object", properties: { period: { type: "string", description: "Report period (week, month, year)" }, dateMin: { type: "string", description: "Start date" }, dateMax: { type: "string", description: "End date" } }, }, }, { name: "get_coupons", description: "Get WooCommerce coupons", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of coupons per page" }, page: { type: "number", description: "Page number" } }, }, }, { name: "create_coupon", description: "Create a new coupon", inputSchema: { type: "object", properties: { couponData: { type: "object", description: "Coupon data" } }, required: ["couponData"], }, }, { name: "search_products", description: "Search products by keyword", inputSchema: { type: "object", properties: { search: { type: "string", description: "Search keyword" }, perPage: { type: "number", description: "Number of products per page" } }, required: ["search"], }, }, { name: "get_product_attributes", description: "Get a list of WooCommerce product attributes", inputSchema: { type: "object", properties: { perPage: { type: "number", description: "Number of attributes per page (default: 10)" }, page: { type: "number", description: "Page number (default: 1)" }, context: { type: "string", description: "Request context (view, edit)" } }, }, }, { name: "get_product_attribute", description: "Get a specific WooCommerce product attribute by ID", inputSchema: { type: "object", properties: { attributeId: { type: "string", description: "Product attribute ID" } }, required: ["attributeId"], }, }, { name: "create_product_attribute", description: "Create a new WooCommerce product attribute", inputSchema: { type: "object", properties: { attributeData: { type: "object", description: "Product attribute data object" } }, required: ["attributeData"], }, }, { name: "update_product_attribute", description: "Update an existing WooCommerce product attribute", inputSchema: { type: "object", properties: { attributeId: { type: "string", description: "Product attribute ID" }, attributeData: { type: "object", description: "Product attribute data to update" } }, required: ["attributeId", "attributeData"], }, }, { name: "delete_product_attribute", description: "Delete a WooCommerce product attribute", inputSchema: { type: "object", properties: { attributeId: { type: "string", description: "Product attribute ID" }, force: { type: "boolean", description: "Force delete (bypass trash)" } }, required: ["attributeId"], }, }, { name: "batch_update_product_attributes", description: "Batch update WooCommerce product attributes", inputSchema: { type: "object", properties: { batchData: { type: "object", description: "Batch data with create, update, and delete arrays" } }, required: ["batchData"], }, }, ], }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request: any) => { const { name, arguments: args } = request.params; try { switch (name) { case "get_mcp_config": { const useEnvFile = args?.useEnvFile ?? true; const serverName = args?.serverName ?? "woocommerce"; const config = { mcpServers: { [serverName]: { command: "node", args: ["build/index.js"], cwd: process.cwd(), env: useEnvFile ? { WORDPRESS_SITE_URL: "${WORDPRESS_SITE_URL}", WORDPRESS_USERNAME: "${WORDPRESS_USERNAME}", WORDPRESS_PASSWORD: "${WORDPRESS_PASSWORD}", WOOCOMMERCE_CONSUMER_KEY: "${WOOCOMMERCE_CONSUMER_KEY}", WOOCOMMERCE_CONSUMER_SECRET: "${WOOCOMMERCE_CONSUMER_SECRET}" } : undefined } } }; const envTemplate = useEnvFile ? ` # .env file template WORDPRESS_SITE_URL=https://your-site.com WORDPRESS_USERNAME=your-wp-username WORDPRESS_PASSWORD=your-wp-password WOOCOMMERCE_CONSUMER_KEY=your-consumer-key WOOCOMMERCE_CONSUMER_SECRET=your-consumer-secret ` : ""; return { content: [ { type: "text", text: `MCP Server Configuration:\n\n${JSON.stringify(config, null, 2)}${envTemplate}`, }, ], }; } case "get_products": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const filters = args?.filters ?? {}; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), ...filters }); const products = await makeWooCommerceRequest(`products?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(products, null, 2), }, ], }; } case "get_product": { const productId = args?.productId; if (!productId) { throw new McpError(ErrorCode.InvalidParams, "Product ID is required"); } const product = await makeWooCommerceRequest(`products/${productId}`); return { content: [ { type: "text", text: JSON.stringify(product, null, 2), }, ], }; } case "create_product": { const productData = args?.productData; if (!productData) { throw new McpError(ErrorCode.InvalidParams, "Product data is required"); } const product = await makeWooCommerceRequest('products', 'POST', productData); return { content: [ { type: "text", text: JSON.stringify(product, null, 2), }, ], }; } case "update_product": { const productId = args?.productId; const productData = args?.productData; if (!productId || !productData) { throw new McpError(ErrorCode.InvalidParams, "Product ID and product data are required"); } const product = await makeWooCommerceRequest(`products/${productId}`, 'PUT', productData); return { content: [ { type: "text", text: JSON.stringify(product, null, 2), }, ], }; } case "delete_product": { const productId = args?.productId; const force = args?.force ?? false; if (!productId) { throw new McpError(ErrorCode.InvalidParams, "Product ID is required"); } const queryParams = force ? '?force=true' : ''; const result = await makeWooCommerceRequest(`products/${productId}${queryParams}`, 'DELETE'); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "get_product_categories": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const filters = args?.filters ?? {}; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), ...filters }); const categories = await makeWooCommerceRequest(`products/categories?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(categories, null, 2), }, ], }; } case "create_product_category": { const categoryData = args?.categoryData; if (!categoryData) { throw new McpError(ErrorCode.InvalidParams, "Category data is required"); } const category = await makeWooCommerceRequest('products/categories', 'POST', categoryData); return { content: [ { type: "text", text: JSON.stringify(category, null, 2), }, ], }; } case "get_orders": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const filters = args?.filters ?? {}; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), ...filters }); const orders = await makeWooCommerceRequest(`orders?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(orders, null, 2), }, ], }; } case "get_order": { const orderId = args?.orderId; if (!orderId) { throw new McpError(ErrorCode.InvalidParams, "Order ID is required"); } const order = await makeWooCommerceRequest(`orders/${orderId}`); return { content: [ { type: "text", text: JSON.stringify(order, null, 2), }, ], }; } case "get_customers": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const filters = args?.filters ?? {}; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), ...filters }); const customers = await makeWooCommerceRequest(`customers?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(customers, null, 2), }, ], }; } case "create_customer": { const customerData = args?.customerData; if (!customerData) { throw new McpError(ErrorCode.InvalidParams, "Customer data is required"); } const customer = await makeWooCommerceRequest('customers', 'POST', customerData); return { content: [ { type: "text", text: JSON.stringify(customer, null, 2), }, ], }; } case "get_sales_report": { const period = args?.period ?? 'week'; const dateMin = args?.dateMin; const dateMax = args?.dateMax; const queryParams = new URLSearchParams({ period }); if (dateMin) queryParams.append('date_min', dateMin); if (dateMax) queryParams.append('date_max', dateMax); const report = await makeWooCommerceRequest(`reports/sales?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(report, null, 2), }, ], }; } case "get_coupons": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), }); const coupons = await makeWooCommerceRequest(`coupons?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(coupons, null, 2), }, ], }; } case "create_coupon": { const couponData = args?.couponData; if (!couponData) { throw new McpError(ErrorCode.InvalidParams, "Coupon data is required"); } const coupon = await makeWooCommerceRequest('coupons', 'POST', couponData); return { content: [ { type: "text", text: JSON.stringify(coupon, null, 2), }, ], }; } case "search_products": { const search = args?.search; const perPage = args?.perPage ?? 10; if (!search) { throw new McpError(ErrorCode.InvalidParams, "Search keyword is required"); } const queryParams = new URLSearchParams({ search, per_page: perPage.toString(), }); const products = await makeWooCommerceRequest(`products?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(products, null, 2), }, ], }; } case "get_product_attributes": { const perPage = args?.perPage ?? 10; const page = args?.page ?? 1; const context = args?.context; const queryParams = new URLSearchParams({ per_page: perPage.toString(), page: page.toString(), }); if (context) { queryParams.append('context', context); } const attributes = await makeWooCommerceRequest(`products/attributes?${queryParams}`); return { content: [ { type: "text", text: JSON.stringify(attributes, null, 2), }, ], }; } case "get_product_attribute": { const attributeId = args?.attributeId; if (!attributeId) { throw new McpError(ErrorCode.InvalidParams, "Product attribute ID is required"); } const attribute = await makeWooCommerceRequest(`products/attributes/${attributeId}`); return { content: [ { type: "text", text: JSON.stringify(attribute, null, 2), }, ], }; } case "create_product_attribute": { const attributeData = args?.attributeData; if (!attributeData) { throw new McpError(ErrorCode.InvalidParams, "Product attribute data is required"); } const attribute = await makeWooCommerceRequest('products/attributes', 'POST', attributeData); return { content: [ { type: "text", text: JSON.stringify(attribute, null, 2), }, ], }; } case "update_product_attribute": { const attributeId = args?.attributeId; const attributeData = args?.attributeData; if (!attributeId || !attributeData) { throw new McpError(ErrorCode.InvalidParams, "Product attribute ID and attribute data are required"); } const attribute = await makeWooCommerceRequest(`products/attributes/${attributeId}`, 'PUT', attributeData); return { content: [ { type: "text", text: JSON.stringify(attribute, null, 2), }, ], }; } case "delete_product_attribute": { const attributeId = args?.attributeId; const force = args?.force ?? false; if (!attributeId) { throw new McpError(ErrorCode.InvalidParams, "Product attribute ID is required"); } const queryParams = force ? '?force=true' : ''; const result = await makeWooCommerceRequest(`products/attributes/${attributeId}${queryParams}`, 'DELETE'); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } case "batch_update_product_attributes": { const batchData = args?.batchData; if (!batchData) { throw new McpError(ErrorCode.InvalidParams, "Batch data is required"); } const result = await makeWooCommerceRequest('products/attributes/batch', 'POST', batchData); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${String(error)}`); } }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("WooCommerce MCP Server running on stdio"); } main().catch((error) => { console.error("Server failed to start:", error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kenan7/woocommerce-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server