This commit is contained in:
Your Name committed 2026-10-11 06:43:08 +07:00
1 parent 9237c0eded
commit f5893c3fad
16 files changed
+1230 -114

No files matched your search

+45 -2
View File
@@ -2,7 +2,7 @@
> HomAroma is the reference tenant. This server exposes shared MCP capabilities; a tool call must use the active tenant's data and configuration.
MCP server สำหรับเชื่อม AI tools เข้ากับ backend ของ HomAroma ผ่าน stdio transport
MCP server สำหรับเชื่อม AI tools เข้ากับ backend ของ DBK Platform ผ่าน stdio transport โดยใช้ข้อมูลและการตั้งค่าของ tenant ที่กำลังเชื่อมต่อ
## Run
@@ -20,7 +20,27 @@ bun run dev
## Environment
รองรับตัวแปรต่อไปนี้:
### Multi-customer target profiles (recommended)
MCP process เดียวสลับ backend ลูกค้าหลายรายได้ด้วย allowlist ใน private JSON registry ตัวอย่างโครงสร้างอยู่ที่ [target-profiles.example.json](./target-profiles.example.json) ให้คัดลอกไปยัง absolute path **นอก Git** แล้วกำหนด:
- `MCP_TARGET_PROFILES_FILE` = absolute path ของ registry
- `MCP_DEFAULT_TARGET_PROFILE` = profile ID ที่เริ่มใช้งานทุกครั้งหลัง restart
- ตัวแปร username/password ที่แต่ละ profile ระบุใน `usernameEnv` และ `passwordEnv` ผ่าน secret store หรือ environment ของ MCP client
Registry เก็บเพียง `id`, `displayName`, `kind` (`local`/`staging`/`production`), `baseUrl`, และ **ชื่อตัวแปร** credential; ห้ามใส่รหัสผ่านจริงใน JSON หรือ Git แต่ละ profile ต้องใช้ชื่อตัวแปร credential แยกกัน ไม่รับ URL ซ้ำกัน และตรวจว่าทุก secret มีค่าก่อนเริ่ม server URL ระยะไกลต้องเป็น HTTPS; HTTP อนุญาตเฉพาะ loopback หาก config ผิด server จะไม่เริ่ม
ใน profile mode ใช้ `list_target_profiles` → `select_target_profile` ด้วย ID → `get_target_environment` เพื่อยืนยัน URL ก่อนเขียน ทุก backend-facing tool ต้องส่ง `expectedProfileId` ให้ตรงกับ active profile; หากแชตอื่นสลับเป้าหมายระหว่างนั้น คำขอจะถูกปฏิเสธก่อนแตะ backend คำขอ MCP ถูกประมวลผลแบบเรียงลำดับเพื่อไม่ให้การสลับ target ตัดกลางคำขอ; auth token เก็บแยกตาม profile การเรียก `set_target_environment` รวมทั้ง `customUrl` จะถูกปฏิเสธ และไม่ fallback ไป URL หรือ admin credential ชุด legacy การเปลี่ยน active profile มีผลเฉพาะ process ปัจจุบัน; restart กลับไป `MCP_DEFAULT_TARGET_PROFILE`
Registry เป็น allowlist ของปลายทาง **ไม่ใช่ระบบ authorization แยกตามแชต/ผู้ใช้** ทุก client ที่เข้าถึง MCP process เดียวกันสามารถเลือกทุก profile ใน registry ได้ และ `expectedProfileId` ป้องกันการส่งคำขอไปผิดเป้าหมายโดยไม่ตั้งใจเท่านั้น หากลูกค้าอยู่คนละ trust group ให้ใช้ MCP process และ registry แยกกัน
`upload_product_image_from_url` ถูกซ่อนและปฏิเสธใน profile mode เพราะตัวดาวน์โหลดเดิมรับ URL ภายนอกโดยไม่มี outbound allowlist หรือ resource limits; legacy mode ยังคง behavior เดิม ระหว่างนี้ให้ใช้ workflow อัปโหลดที่ผ่านการตรวจความปลอดภัยจากระบบอื่น
**Migration:** ตั้ง registry และ secret environment ทุก profile ให้ครบก่อนเปิด `MCP_TARGET_PROFILES_FILE` แล้ว restart MCP client ตรวจ `get_target_environment` ว่า mode เป็น `profiles` และ ID/URL ถูกต้องก่อนใช้ tool เขียนข้อมูล อย่าคัดลอก URL หรือ credential ของลูกค้าจริงลงตัวอย่างใน repository
### Legacy mode (no registry)
รองรับตัวแปรต่อไปนี้เพื่อความเข้ากันได้:
- `MCP_BACKEND_URL` สำหรับกำหนด backend target ตรง ๆ
- `MCP_BACKEND_URL_LOCAL` ค่าเริ่มต้นสำหรับ local
@@ -30,12 +50,35 @@ bun run dev
ถ้าไม่ตั้งค่า `MCP_BACKEND_URL` server จะเริ่มที่ local backend และสลับเป็น production ได้ด้วย tool `set_target_environment`
ชื่อ `homaroma` ที่ยังอยู่ใน package, server identity, config key หรือ URL เป็น legacy runtime identifier เพื่อความเข้ากันได้ ไม่ใช่ชื่อแพลตฟอร์มหรือค่าแบรนด์สำหรับทุก tenant การเปลี่ยน identifier เหล่านี้ต้องทำเป็น migration แยกต่างหาก
ข้อควรระวังใน legacy mode: `set_target_environment` ยังใช้ admin credential ชุดเดียวกับทุก backend; `production` ยังมี HomAroma URL เป็น fallback หากไม่ได้กำหนด `MCP_BACKEND_URL_PRODUCTION` และ `customUrl` รับ URL อิสระ จึงไม่ควรใช้ legacy mode เพื่อสลับหลายลูกค้า
legacy mode ยังมีค่า admin สำรองในโค้ดตามการตัดสินใจชั่วคราวของเจ้าของโปรเจกต์ ควรกำหนด `MCP_ADMIN_USERNAME` และ `MCP_ADMIN_PASSWORD` ในสภาพแวดล้อมของ MCP client และย้ายออกจากค่าสำรองในรอบ migration ถัดไป อย่าใส่รหัสผ่านในแชตหรือ commit ลง repository ค่า fallback นี้ **ไม่ถูกใช้ใน profile mode**
## Available tools
- `upload_cms_asset` อัปโหลด JPEG/PNG/WebP/GIF จากไฟล์ในเครื่องเข้า Media Library ของ backend ปัจจุบัน แล้วคืน `url` และ `path` สำหรับ `ARTICLE_MEDIA` / `ARTICLE_GALLERY` โดยไม่ผูกกับสินค้า ต้องตั้ง `MCP_ASSET_ROOT` เป็น absolute directory ของไฟล์ที่อนุญาตก่อน restart; ส่ง `filePath` แบบ absolute ภายใน directory นั้น ขนาดไม่เกิน 10 MiB และใน profile mode ต้องส่ง `expectedProfileId` ด้วย Tool ตรวจ real path, ชนิดไฟล์จากนามสกุลและ magic bytes; ไม่รับ URL ภายนอก, SVG หรือ base64 การอัปโหลดสร้าง Media record แม้ยังไม่เพิ่มภาพลงหน้า CMS ให้ตรวจ target ด้วย `get_target_environment` ก่อนเสมอ
- `update_brand_name` เปลี่ยนชื่อแบรนด์กลางที่ใช้ใน header/footer ของ `apps/spa` และ `apps/website`
- `update_store_settings_translation` อัปเดตข้อความแปลของ store settings
- `update_footer_content` อัปเดตคำอธิบายแบรนด์และ social links เท่านั้น
- `get_footer_brand` / `update_footer_brand` อ่านและแก้ Footer Brand block โดยตรง (brand name, logo, คำอธิบายแยกภาษา, social links) พร้อม `dryRun` และ `expectedVersion`
- `get_footer_layout` / `patch_footer_layout` อ่านและแก้โครง Footer พร้อม preview และการตรวจ version ก่อนเขียน
- `get_category_sections` / `seed_category_sections` / `add_category_section` / `update_category_section` / `reorder_category_sections` / `delete_category_section` จัดการ section ของหน้า Category
Tool definitions มี annotation บอกการอ่านอย่างเดียวหรือการลบ และผลลัพธ์ JSON มี `structuredContent` เพิ่มจากข้อความเดิมเพื่อให้ LLM ใช้ง่ายขึ้น โดยยังเข้ากันได้กับ client ที่อ่าน `content` อยู่
ตัวอย่างจาก `get_page_block_schema` เป็นโครง payload สำหรับเริ่มต้น ไม่ใช่เนื้อหาที่ควรเผยแพร่ทันที ให้แทน URL ตัวอย่าง ข้อความ ผู้เขียน และช่องทางติดต่อด้วยข้อมูลที่ตรวจสอบแล้วของ tenant ปัจจุบันก่อนเขียนจริง โดยเฉพาะ `CONTACT_INFO` ที่มี email และ LINE ID เป็น placeholder
## Safe editing workflow
1. เรียก `get_target_environment` ก่อนแก้ข้อมูล โดยเฉพาะหลัง restart; ใน profile mode ยืนยันทั้ง profile ID และ URL อย่าเขียน production ถ้าผู้ใช้ไม่ได้ขอชัดเจน
2. อ่านข้อมูลเป้าหมายก่อน แล้วเลือก tool ที่เฉพาะงาน
3. ใช้ `dryRun: true` เมื่อมี, ตรวจผล preview แล้วค่อยเขียนจริง
4. ส่ง `expectedVersion` สำหรับ Footer layout และงานอื่นที่รองรับ version
5. อ่านข้อมูลซ้ำหลังเขียนเพื่อตรวจผล
Category section tools ทำ preview ฝั่ง MCP เท่านั้น เพราะ backend ปัจจุบันยังไม่มี `dryRun` หรือ version check แบบ atomic สำหรับ endpoint กลุ่มนี้ ข้อมูลอาจเปลี่ยนระหว่าง preview กับการเขียนจริง; ให้ตรวจรายการล่าสุดก่อนเขียนเสมอ
## Footer Menu LLM Workflow