x
This commit is contained in:
1 parent
ed69a4b840
commit
992335a52b
22 files changed
+1064
-346
No files matched your search
+61
-30
@@ -80,15 +80,26 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
description: "Ping the backend to verify connection and authentication",
|
||||
inputSchema: { type: "object", properties: {} },
|
||||
},
|
||||
{
|
||||
name: "list_product_brands",
|
||||
description: "List all product brands with their translations",
|
||||
inputSchema: { type: "object", properties: {} }
|
||||
},
|
||||
{
|
||||
name: "list_categories",
|
||||
description: "List all product categories with their translations",
|
||||
inputSchema: { type: "object", properties: {} }
|
||||
},
|
||||
{
|
||||
name: "search_products",
|
||||
description: "Search for products and get their basic info",
|
||||
description: "Search for products and get their basic info. WARNING: Set a low 'limit' (e.g. 5) to prevent token overflow, as product details are massive.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
search: { type: "string", description: "Search term" },
|
||||
limit: { type: "number", description: "Max results" },
|
||||
lang: { type: "string", description: "Language code (e.g. th, en, all)" }
|
||||
lang: { type: "string", description: "Language code (e.g. th, en, all)" },
|
||||
brandId: { type: "number", description: "Filter by brand ID" }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -118,14 +129,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "update_scent_translation",
|
||||
description: "Add or update translations for a specific scent.",
|
||||
name: "update_product_brand_translation",
|
||||
description: "Add or update translations for a specific product brand.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "number", description: "Scent ID" },
|
||||
id: { type: "number", description: "Brand ID" },
|
||||
lang: { type: "string", description: "Language code (th, en, ja, zh, vi, ko)" },
|
||||
name: { type: "string", description: "Translated scent name" }
|
||||
name: { type: "string", description: "Translated brand name" }
|
||||
},
|
||||
required: ["id", "lang", "name"]
|
||||
}
|
||||
@@ -240,9 +251,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
required: ["id", "lang"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "create_product",
|
||||
description: "Create a new product. Minimum required fields are categoryId and brandId.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
categoryId: { type: "number" },
|
||||
brandId: { type: "number" },
|
||||
name: { type: "string" },
|
||||
price: { type: "number" },
|
||||
description: { type: "string" },
|
||||
details: { type: "string" }
|
||||
},
|
||||
required: ["categoryId", "brandId"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "update_product_content",
|
||||
description: "Update product basic content (name, description, details)",
|
||||
description: "Update product basic content for the default/Thai translation. Note: If the Thai translation record does not exist yet, the 'name' field is strictly required, otherwise the backend will silently drop the update.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
@@ -256,7 +283,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
},
|
||||
{
|
||||
name: "update_product_translation",
|
||||
description: "Update product translation for a specific language. Use this to add missing translations.",
|
||||
description: "Update product translation for a specific language. Use this to add missing translations. Note: If adding a missing translation, the 'name' field is strictly required by the backend, otherwise the update will silently fail.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
@@ -355,7 +382,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
slug: { type: "string", description: "Slug of the page" }
|
||||
slug: { type: "string", description: "Slug of the page" },
|
||||
includeInactive: { type: "boolean", description: "Include inactive sections" }
|
||||
},
|
||||
required: ["slug"]
|
||||
}
|
||||
@@ -367,16 +395,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string", description: "Title of the page" },
|
||||
slug: { type: "string", description: "Unique slug identifier (e.g. about-us)" },
|
||||
slug: { type: "string", description: "Unique slug identifier. Do not use reserved system slugs (e.g., shop, category, cart, checkout, account, article, etc.)." },
|
||||
isPublished: { type: "boolean", description: "Publish status" },
|
||||
status: { type: "string", description: "Publish status (e.g. 'published' or 'draft')" },
|
||||
metadata: { type: "object", description: "SEO metadata" },
|
||||
id: { type: "number", description: "Numeric page ID (if updating existing page)" }
|
||||
id: { type: "number", description: "Numeric page ID. Required if you are updating an existing page. Use list_dynamic_pages_metadata or get_dynamic_page_detail to find the ID first." }
|
||||
},
|
||||
required: ["title", "slug"]
|
||||
}
|
||||
},
|
||||
...SECTION_TOOL_DEFINITIONS,
|
||||
{
|
||||
name: "update_footer_content",
|
||||
description: "Update the content and links of the 4 Footer Blocks (Brand, Explore, Collections, Newsletter)",
|
||||
@@ -465,11 +492,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const res = await api.get(`/menus/${params.name}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "list_product_brands": {
|
||||
const res = await api.get(`/products/brands`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "list_categories": {
|
||||
const res = await api.get(`/categories`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "search_products": {
|
||||
const search = params.search ? `&search=${encodeURIComponent(params.search)}` : "";
|
||||
const limit = params.limit ? `&limit=${params.limit}` : "&limit=10";
|
||||
const lang = params.lang ? `&lang=${params.lang}` : "";
|
||||
const res = await api.get(`/products?${search}${limit}${lang}`);
|
||||
const brandId = params.brandId ? `&brandId=${params.brandId}` : "";
|
||||
const res = await api.get(`/products?${search}${limit}${lang}${brandId}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "get_product_detail": {
|
||||
@@ -477,6 +513,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const res = await api.get(`/products/${params.id}${lang}`);
|
||||
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) }] };
|
||||
}
|
||||
case "update_category_translation": {
|
||||
const { id, lang, name } = params as any;
|
||||
const res = await api.patch(`/categories/${id}/translations`, {
|
||||
@@ -486,9 +526,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }]
|
||||
};
|
||||
}
|
||||
case "update_scent_translation": {
|
||||
case "update_product_brand_translation": {
|
||||
const { id, lang, name } = params as any;
|
||||
const res = await api.patch(`/products/scents/${id}/translations`, {
|
||||
const res = await api.patch(`/products/brands/${id}/translations`, {
|
||||
name: { [lang]: name }
|
||||
});
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
@@ -636,22 +676,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
});
|
||||
const uploadedUrl = uploadRes.data.url;
|
||||
|
||||
// 3. Get current product to append image
|
||||
const prodRes = await api.get(`/products/${params.productId}`);
|
||||
const product = prodRes.data;
|
||||
const newImages = [...product.images, { url: uploadedUrl, order: product.images.length }];
|
||||
|
||||
// 4. Update product (using PUT to sync variants and images)
|
||||
// Ensure we pass required fields
|
||||
const putRes = await api.put(`/products/${params.productId}`, {
|
||||
categoryId: product.categoryId,
|
||||
description: product.description,
|
||||
details: product.details,
|
||||
variants: product.variants,
|
||||
images: newImages
|
||||
// 3. Post the new image URL directly to the product
|
||||
const postRes = await api.post(`/products/${params.productId}/images`, {
|
||||
url: uploadedUrl
|
||||
});
|
||||
|
||||
return { content: [{ type: "text", text: `Image uploaded and product updated. New image URL: ${uploadedUrl}` }] };
|
||||
return { content: [{ type: "text", text: JSON.stringify({ success: true, imageUrl: uploadedUrl }, null, 2) }] };
|
||||
}
|
||||
case "generate_mock_review": {
|
||||
const res = await api.post("/reviews", {
|
||||
@@ -708,7 +738,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
return { content: [{ type: "text", text: JSON.stringify(metadata, null, 2) }] };
|
||||
}
|
||||
case "get_dynamic_page_detail": {
|
||||
const res = await api.get(`/pages/${params.slug}`);
|
||||
const url = `/pages/${params.slug}` + (params.includeInactive ? "?includeInactive=true" : "");
|
||||
const res = await api.get(url);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "create_dynamic_page": {
|
||||
|
||||
Reference in new issue
Block a user