x
This commit is contained in:
1 parent
c23a4723ed
commit
07e9413a6b
13 files changed
+497
-94
No files matched your search
+119
-9
@@ -253,24 +253,49 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
},
|
||||
{
|
||||
name: "create_product",
|
||||
description: "Create a new product, optionally including its options and variant matrix. Minimum required fields are categoryId and brandId.",
|
||||
description: "Create a new product, optionally including its options and variant matrix. Provide categoryId/brandId OR categoryName/brandName.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
categoryId: { type: "number" },
|
||||
categoryName: { type: "string" },
|
||||
brandId: { type: "number" },
|
||||
brandName: { type: "string" },
|
||||
name: { type: "string" },
|
||||
description: { type: "string" },
|
||||
details: { type: "string" },
|
||||
price: { type: "number", description: "Base price if no variants are provided" },
|
||||
options: {
|
||||
type: "array",
|
||||
description: "Array of option definitions (max 3). E.g., [{'name': 'Size', 'values': ['S', 'M']}]",
|
||||
items: {
|
||||
translations: {
|
||||
type: "object",
|
||||
description: "Object with lang codes as keys (e.g. 'th', 'en') and {name, description, details} as values",
|
||||
additionalProperties: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
values: { type: "array", items: { type: "string" } }
|
||||
description: { type: "string" },
|
||||
details: { type: "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
type: "array",
|
||||
description: "Array of option definitions (max 3). E.g., [{'name': {'th': 'ขนาด'}, 'values': [{'th': 'เล็ก'}, {'en': 'Small'}]}]",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
type: "object",
|
||||
description: "Object with lang codes as keys, e.g. {'th': 'ขนาด', 'en': 'Size'}",
|
||||
additionalProperties: { type: "string" }
|
||||
},
|
||||
values: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
description: "Object with lang codes as keys",
|
||||
additionalProperties: { type: "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["name", "values"]
|
||||
}
|
||||
@@ -292,8 +317,80 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
required: ["option1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "bulk_create_products",
|
||||
description: "Create multiple products at once. Each object in the array has the same schema as create_product.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
products: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
categoryId: { type: "number" },
|
||||
categoryName: { type: "string" },
|
||||
brandId: { type: "number" },
|
||||
brandName: { type: "string" },
|
||||
name: { type: "string" },
|
||||
description: { type: "string" },
|
||||
details: { type: "string" },
|
||||
price: { type: "number" },
|
||||
translations: {
|
||||
type: "object",
|
||||
additionalProperties: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
description: { type: "string" },
|
||||
details: { type: "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" }
|
||||
},
|
||||
values: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["name", "values"]
|
||||
}
|
||||
},
|
||||
variants: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sku: { type: "string" },
|
||||
barcode: { type: "string" },
|
||||
price: { type: "number" },
|
||||
stock: { type: "number", default: 0 },
|
||||
option1: { type: "string" },
|
||||
option2: { type: "string" },
|
||||
option3: { type: "string" }
|
||||
},
|
||||
required: ["option1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["categoryId", "brandId"]
|
||||
required: ["products"]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -309,8 +406,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
values: { type: "array", items: { type: "string" } }
|
||||
name: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" }
|
||||
},
|
||||
values: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: { type: "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["name", "values"]
|
||||
}
|
||||
@@ -585,6 +691,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const res = await api.post(`/products`, params);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "bulk_create_products": {
|
||||
const res = await api.post(`/products/bulk`, params.products);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "sync_product_variants": {
|
||||
const payload = {
|
||||
options: params.options,
|
||||
|
||||
@@ -203,14 +203,33 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
}
|
||||
case "upsert_menu": {
|
||||
const dryRun = !!params.dryRun;
|
||||
const items = Array.isArray(params.items) ? params.items : [];
|
||||
let existingMenu: any = null;
|
||||
try {
|
||||
const getRes = await api.get(`/menus/${params.name}`);
|
||||
existingMenu = getRes.data;
|
||||
} catch (e) {
|
||||
// Menu might not exist yet
|
||||
}
|
||||
|
||||
const items = params.items !== undefined ? (Array.isArray(params.items) ? params.items : []) : (existingMenu?.items || []);
|
||||
const body: any = { items };
|
||||
const itemCheck = validateMenuItems(items);
|
||||
if (itemCheck.issues.length > 0) {
|
||||
throw new Error(`Invalid menu items: ${itemCheck.issues.join("; ")}`);
|
||||
}
|
||||
if (params.payload !== undefined) body.payload = params.payload;
|
||||
if (params.isActive !== undefined) body.isActive = params.isActive;
|
||||
|
||||
if (params.payload !== undefined) {
|
||||
body.payload = params.payload;
|
||||
} else if (existingMenu?.payload !== undefined) {
|
||||
body.payload = existingMenu.payload;
|
||||
}
|
||||
|
||||
if (params.isActive !== undefined) {
|
||||
body.isActive = params.isActive;
|
||||
} else if (existingMenu?.isActive !== undefined) {
|
||||
body.isActive = existingMenu.isActive;
|
||||
}
|
||||
|
||||
if (params.payload !== undefined && !isPlainObject(params.payload) && !Array.isArray(params.payload)) {
|
||||
throw new Error("Invalid menu payload: payload must be an object or array");
|
||||
}
|
||||
@@ -228,9 +247,9 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
menuName: params.name,
|
||||
preview: {
|
||||
name: params.name,
|
||||
items: cloneMenuValue(items),
|
||||
payload: params.payload !== undefined ? cloneMenuValue(params.payload) : undefined,
|
||||
isActive: params.isActive
|
||||
itemCount: items.length,
|
||||
hasPayload: !!body.payload,
|
||||
isActive: body.isActive
|
||||
},
|
||||
warnings: itemCheck.warnings
|
||||
},
|
||||
@@ -243,7 +262,25 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
}
|
||||
|
||||
const res = await api.put(`/menus/${params.name}`, body);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{
|
||||
success: true,
|
||||
operation: "upsert_menu",
|
||||
name: res.data.name,
|
||||
isActive: res.data.isActive,
|
||||
itemCount: res.data.items?.length || 0,
|
||||
hasPayload: !!res.data.payload
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
case "audit_missing_pages": {
|
||||
const menusRes = await api.get("/menus");
|
||||
@@ -373,7 +410,7 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify(
|
||||
{ success: true, dryRun: true, operation: "bulk_menu_operations", menuName: params.name, warnings: result.warnings, applied: result.applied, preview: { payload: result.payload } },
|
||||
{ success: true, dryRun: true, operation: "bulk_menu_operations", menuName: params.name, warnings: result.warnings, applied: result.applied, preview: { nodeCount: result.payload.length } },
|
||||
null,
|
||||
2
|
||||
)
|
||||
@@ -392,7 +429,7 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({ success: true, operation: "bulk_menu_operations", menuName: params.name, warnings: result.warnings, applied: result.applied, menu: writeRes.data }, null, 2)
|
||||
text: JSON.stringify({ success: true, operation: "bulk_menu_operations", menuName: params.name, warnings: result.warnings, applied: result.applied, nodeCount: normalized.payload.length }, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -413,14 +450,14 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "add_menu_node", nodeId: result.nodeId, warnings: validation.warnings, preview: result.payload }, null, 2)
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "add_menu_node", nodeId: result.nodeId, warnings: validation.warnings, preview: { nodeCount: result.payload.length } }, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
await api.put(`/menus/main`, { payload: result.payload, items: menu.items || [] });
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeId: result.nodeId, payload: result.payload }, null, 2) }] };
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeId: result.nodeId, nodeCount: result.payload.length }, null, 2) }] };
|
||||
}
|
||||
case "update_menu_translation": {
|
||||
const { nodeId, translations } = params;
|
||||
@@ -438,14 +475,14 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "update_menu_translation", warnings: validation.warnings, preview: result.payload }, null, 2)
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "update_menu_translation", warnings: validation.warnings, preview: { nodeCount: result.payload.length } }, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
await api.put(`/menus/main`, { payload: result.payload, items: menu.items || [] });
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeId, payload: result.payload }, null, 2) }] };
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeId, nodeCount: result.payload.length }, null, 2) }] };
|
||||
}
|
||||
case "move_menu_node": {
|
||||
const { nodeId, newParentId, orderIndex } = params;
|
||||
@@ -459,14 +496,14 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "move_menu_node", preview: result.payload }, null, 2)
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "move_menu_node", preview: { nodeCount: result.payload.length } }, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
await api.put(`/menus/main`, { payload: result.payload, items: menu.items || [] });
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, payload: result.payload }, null, 2) }] };
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeCount: result.payload.length }, null, 2) }] };
|
||||
}
|
||||
case "remove_menu_node": {
|
||||
const { nodeId } = params;
|
||||
@@ -480,14 +517,14 @@ export async function handleMenuTool(api: AxiosInstance, name: string, params: a
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "remove_menu_node", removedNode: result.removedNode, preview: result.payload }, null, 2)
|
||||
text: JSON.stringify({ success: true, dryRun: true, operation: "remove_menu_node", removedNode: result.removedNode, preview: { nodeCount: result.payload.length } }, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
await api.put(`/menus/main`, { payload: result.payload, items: menu.items || [] });
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, payload: result.payload }, null, 2) }] };
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, nodeCount: result.payload.length }, null, 2) }] };
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
|
||||
Reference in new issue
Block a user