209 lines
8.1 KiB
Markdown
209 lines
8.1 KiB
Markdown
# HomAroma MCP Guide for LLMs
|
||
|
||
This guide explains how to use the HomAroma MCP tools safely and consistently.
|
||
|
||
## Core Rules
|
||
|
||
- Prefer the dedicated block tools over the generic `add_page_section` / `update_page_section` tools when available.
|
||
- Use `update_page_translations` when you need to set several languages for a page title in one call.
|
||
- Treat localized fields and plain strings differently.
|
||
- Read back the page after edits when you need confirmation.
|
||
|
||
## Finding a Page
|
||
|
||
- Use `get_dynamic_page_detail` with the page slug when you already know the slug.
|
||
- Use `list_dynamic_pages_metadata` when you need to search all pages quickly.
|
||
- The dynamic page detail response includes the page `id`, which is the `pageId` you use for section tools.
|
||
|
||
## Create Page Response Contract
|
||
|
||
Use `create_page_with_section` only when the slug does not exist. It atomically
|
||
creates a new page and its first section; it does not update an existing page.
|
||
If it returns `PAGE_SLUG_EXISTS`, use the returned `pageId` with
|
||
`add_page_section`.
|
||
|
||
To add another block to an existing page:
|
||
|
||
1. Call `get_dynamic_page_detail` with the slug.
|
||
2. Call `get_page_block_schema` for the desired block type.
|
||
3. Call `add_page_section` with the returned page `id`.
|
||
4. Call `reorder_page_sections` if the new block must move relative to existing blocks.
|
||
5. Read the page back with `get_dynamic_page_detail`.
|
||
|
||
`create_dynamic_page` now returns a structured response that is easy for LLMs to parse:
|
||
|
||
- `success`
|
||
- `operation`
|
||
- `pageId`
|
||
- `slug`
|
||
- `title`
|
||
- `isPublished`
|
||
- `diagnostic`
|
||
- `page`
|
||
|
||
Use `diagnostic` as the human-readable explanation, not as the only signal of success.
|
||
|
||
## Section Tool Mapping
|
||
|
||
- `update_hero_article`
|
||
- `update_rich_text`
|
||
- `update_scent_notes_breakdown`
|
||
- `update_quote_callout`
|
||
- `update_product_carousel`
|
||
- `update_accordion`
|
||
- `update_contact_info`
|
||
- `update_contact_form`
|
||
|
||
These tools return a normalized response with:
|
||
|
||
- `success`
|
||
- `tool`
|
||
- `sectionType`
|
||
- `sectionId`
|
||
- `updatedFields`
|
||
- `appliedPayload`
|
||
- `notes`
|
||
- `section`
|
||
|
||
## Payload Shape Cheat Sheet
|
||
|
||
### Localized string
|
||
|
||
Use this when a field can be translated:
|
||
|
||
```json
|
||
{ "th": "ข้อความภาษาไทย", "en": "English text" }
|
||
```
|
||
|
||
### Plain string
|
||
|
||
Use one string only for URLs, slugs, IDs, and booleans/numbers as appropriate.
|
||
|
||
## Block-Specific Rules
|
||
|
||
### `HERO_ARTICLE`
|
||
|
||
- Localized: `title`, `subtitle`, `author`, `category`
|
||
- Plain string: `publishDate`, `date`, `imageUrl`, `backgroundImageUrl`, `overlayColor`
|
||
- The image is passed as a URL string in `imageUrl`
|
||
|
||
### `RICH_TEXT`
|
||
|
||
- `title` is optional and localized
|
||
- `content` is required and localized
|
||
- HTML is allowed in `content`
|
||
|
||
### `ARTICLE_MEDIA`
|
||
|
||
- `body` is required, localized plain text; do not send HTML
|
||
- `heading`, `imageAlt`, and `imageCaption` are localized
|
||
- `imageUrl` is a plain URL or website-relative media path
|
||
- `imageAlt` is required whenever `imageUrl` is present
|
||
- `imagePosition` accepts `left`, `right`, or `top`
|
||
- `width` accepts `narrow`, `standard`, or `wide`
|
||
- `background` accepts `default` or `muted`
|
||
|
||
### Article composition blocks
|
||
|
||
- `ARTICLE_HEADER`: article title, subtitle, category, author, date, and optional cover image
|
||
- `ARTICLE_GALLERY`: 2–8 images with required localized alt text; layouts are `grid` or `featured`
|
||
- `ARTICLE_FACTS`: 1–8 concise facts or key takeaways
|
||
- `ARTICLE_VIDEO`: HTTPS YouTube, Vimeo, or direct video URL; embed HTML is not accepted
|
||
- `ARTICLE_REFERENCES`: 1–20 references with optional verified HTTPS URLs and notes
|
||
- `ARTICLE_TABLE`: responsive technical comparison with 2–6 columns
|
||
- `ARTICLE_DOWNLOAD`: 1–10 verified HTTPS documents
|
||
- `ARTICLE_CTA`: one primary action and an optional secondary action
|
||
- Reuse `QUOTE_CALLOUT`, `ACCORDION`, and `PRODUCT_CAROUSEL` instead of creating duplicate article-only variants
|
||
|
||
### `SCENT_NOTES_BREAKDOWN`
|
||
|
||
- `title` and `description` are localized
|
||
- Each note item may be a plain string or a localized string object
|
||
- `heartNotes` and `middleNotes` are mirrored by the backend
|
||
|
||
### `QUOTE_CALLOUT`
|
||
|
||
- `quote` is required and localized
|
||
- `author` and `role` are optional localized fields
|
||
|
||
### `PRODUCT_CAROUSEL`
|
||
|
||
- `title` and `description` are localized
|
||
- `collectionId`, `limit`, `showPrice`, `showAddToCart`, and `products` are plain values
|
||
- If `products` is omitted, the backend can auto-populate products on read-back
|
||
|
||
### `ACCORDION`
|
||
|
||
- `title` is optional and localized
|
||
- `categories` is required
|
||
- Each category needs:
|
||
- localized `name`
|
||
- optional `icon`
|
||
- at least one question
|
||
- Each question needs localized `q` and `a`
|
||
|
||
### `CONTACT_INFO`
|
||
|
||
- `title` is optional and localized
|
||
- `address` and `hours` are localized
|
||
- `email` and `line` are plain strings
|
||
|
||
### `CONTACT_FORM`
|
||
|
||
- `title` and `subtitle` are localized
|
||
- There are no extra fields
|
||
|
||
## Recommended Flow
|
||
|
||
1. Determine whether the page already exists.
|
||
2. For a new page, use `create_page_with_section` for the page and first block.
|
||
3. For an existing page, get its id and use `add_page_section`.
|
||
4. Create or update the page title translations.
|
||
5. Update existing sections using the dedicated block tool when possible.
|
||
6. Read back the page with `get_dynamic_page_detail`.
|
||
7. If a section has auto-populated fields, trust the read-back result over the raw update payload.
|
||
|
||
## Translating Page Builder Blocks
|
||
|
||
Translate one language and one block at a time. This keeps the context compact and prevents a full payload replacement from overwriting existing languages.
|
||
|
||
1. Call `get_page_translation_status` with `pageId` and the target `lang`.
|
||
2. Pick one incomplete `sectionId`.
|
||
3. Call `get_page_section_translation` with that `sectionId` and target `lang`. The default fallback supplies source text for untranslated fields and lists those fields in `fallbackPaths`.
|
||
4. Translate the fields listed in `fallbackPaths`; preserve the payload's object and array shape.
|
||
5. Call `update_section_translation` with `translations` and the `updatedAt` value as `expectedUpdatedAt`.
|
||
6. Read the block again with `get_page_section_translation` and confirm `fallbackPaths` is empty.
|
||
|
||
`update_section_translation` changes only the requested language in registered localized fields. It preserves other languages, URLs, IDs, layout configuration, and other non-translatable values. A `SECTION_VERSION_CONFLICT` response means the block changed after it was read; fetch it again before retrying.
|
||
|
||
Use `get_page_section` with `lang=all` only when every stored language map is genuinely needed. A specific language returns resolved strings and uses fallback by default.
|
||
|
||
## Editing Footer Menus
|
||
|
||
`footer-explore` and `footer-support` are flat menus shared by Admin, Backend, MCP, and Website. They are not Page Builder sections and do not use the Mega Menu tree tools.
|
||
|
||
1. Call `get_footer_menu` with `menuName` and the target `lang`.
|
||
2. Keep the returned `version`.
|
||
3. Preview one item-level mutation with `dryRun=true` and `expectedVersion`.
|
||
4. Apply only after the preview is correct.
|
||
5. Read the menu again and verify the result.
|
||
|
||
Use `update_footer_menu_item_translation` for one language at a time. Use `reorder_footer_menu_items` only with the complete list of current item IDs. If the backend returns `MENU_VERSION_CONFLICT`, discard the old version and read the menu again.
|
||
|
||
An allowed Footer menu may not exist before its first item is saved. In that case, `get_footer_menu` returns `exists=false` and `version=null`. Run `add_footer_menu_item` with `dryRun=true`; a `willCreateMenu=true` preview confirms that the actual add will create the active menu and first item atomically.
|
||
|
||
Do not use legacy `update_footer_content` for menu arrays. It remains available only for the Footer brand description and social links. Website Collections come from Categories, not a Footer menu.
|
||
|
||
## What to Expect
|
||
|
||
- `PRODUCT_CAROUSEL` may return products even when you did not send them.
|
||
- `SCENT_NOTES_BREAKDOWN` may show mirrored note groups in the response.
|
||
- `create_dynamic_page` should now return a clear success/error contract.
|
||
|
||
## Safe Usage Tips
|
||
|
||
- Do not guess the field shape from the UI alone.
|
||
- If a field is a URL, send a URL string.
|
||
- If a field is translated, send a localized object.
|
||
- If you are unsure, inspect an existing page with `get_dynamic_page_detail` first.
|