feat(mcp): add BOM management tools (list_products_bom_status, get_product_bom, set_product_bom)

This commit is contained in:
Your Name committed 2026-10-18 12:25:35 +07:00
1 parent b030c08f68
commit 4fcdd8a816
4 files changed
+538 -1

No files matched your search

+75
View File
@@ -371,6 +371,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
required: ["id"]
}
},
{
name: "list_products_bom_status",
description: "List products and their BOM (Bill of Materials) setup status (whether variants have formulas defined). Useful for finding products needing BOM configuration.",
inputSchema: {
type: "object",
properties: {
search: { type: "string", description: "Search by product name, brand, or SKU" },
status: { type: "string", enum: ["all", "missing", "configured", "partial"], description: "Filter by BOM status. Default is 'all'." },
limit: { type: "number", description: "Maximum products to return. Default 20." }
}
}
},
{
name: "get_product_bom",
description: "Get full BOM formula details, current material costs, gross profit, margin %, and available raw materials for a product. Use this to inspect a product's variants and determine required materials.",
inputSchema: {
type: "object",
properties: {
productId: { type: "number", description: "Product ID" }
},
required: ["productId"]
}
},
{
name: "set_product_bom",
description: "Set or update the BOM (Bill of Materials) formula for a product's variants. Matches variants by variantId or sku, and raw materials by rawMaterialId or name. Replaces the variant's BOM items and recalculates cost/margin.",
inputSchema: {
type: "object",
properties: {
productId: { type: "number", description: "Product ID" },
variants: {
type: "array",
description: "Array of variant BOM formulas to apply",
items: {
type: "object",
properties: {
variantId: { type: "number", description: "Variant ID (optional if sku provided)" },
sku: { type: "string", description: "Variant SKU (optional if variantId provided)" },
bomItems: {
type: "array",
description: "List of raw material ingredients/packaging for this variant",
items: {
type: "object",
properties: {
rawMaterialId: { type: "number", description: "Raw material ID (optional if name provided)" },
name: { type: "string", description: "Raw material name (optional if rawMaterialId provided)" },
quantity: { type: "number", description: "Quantity of raw material used per unit" }
},
required: ["quantity"]
}
}
},
required: ["bomItems"]
}
}
},
required: ["productId", "variants"]
}
},
{
name: "update_category_translation",
description: "Add or update translations for a specific category. Do NOT use this tool for products.",
@@ -1449,6 +1508,22 @@ async function handleToolRequest(request: CallToolRequest) {
const res = await api.get(`/products/${params.id}${lang}`);
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
}
case "list_products_bom_status": {
const query = new URLSearchParams();
if (params.search) query.set("search", String(params.search));
if (params.status) query.set("status", String(params.status));
query.set("limit", String(params.limit ?? 20));
const res = await api.get(`/products/bom-status?${query.toString()}`);
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
}
case "get_product_bom": {
const res = await api.get(`/products/${params.productId}/bom`);
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
}
case "set_product_bom": {
const res = await api.put(`/products/${params.productId}/bom`, { variants: params.variants });
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
}
case "create_product": {
const res = await api.post(`/products`, params);
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };