Skip to content

MCP cho AI agent ​

Máy chủ MCP (Model Context Protocol) để AI agent (Claude, Cursor, ChatGPT, agent tự viết…) làm việc trực tiếp với dữ liệu cửa hàng: đơn hàng, sản phẩm, danh mục, tồn kho, nhà cung cấp, phiếu nhập hàng (nguyên vật liệu), khách hàng, quy trình, đăng bài, giao hàng và KiotViet.

URLhttps://api.sieutroly.ai/api/mcp
Giao thứcStreamable HTTP, không giữ phiên: mỗi yêu cầu JSON-RPC độc lập, phản hồi JSON. Chỉ POST; GET/DELETE → 405
Xác thựcAPI key của workspace: Authorization: Bearer sk_live_… (hoặc X-API-Key). Tạo ở web → API Key
Link MCPhttps://api.sieutroly.ai/api/mcp/mcp_… — nút «Link MCP» trên từng API key, cho client không đặt được header (ChatGPT, Claude «Custom connector», n8n…). Link chỉ mở cửa MCP với đúng quyền của key (không gọi được REST). «Đổi link» làm link cũ hết hiệu lực mà API key giữ nguyên; xoay API key cũng đổi link
Phạm vi dữ liệuĐúng một workspace: workspace của API key

Kết nối ​

Cách nhanh nhất: trang API Key → bấm «Link MCP» trên key → Copy → dán vào ô MCP server URL của agent.

Claude Code

bash
claude mcp add --transport http sieutroly https://api.sieutroly.ai/api/mcp \
  --header "Authorization: Bearer $API_KEY"

Cursor / VS Code / Windsurf (mcp.json)

json
{ "mcpServers": { "sieutroly": { "url": "https://api.sieutroly.ai/api/mcp", "headers": { "Authorization": "Bearer <API_KEY>" } } } }

Claude Desktop (qua mcp-remote, cần Node.js)

json
{ "mcpServers": { "sieutroly": { "command": "npx", "args": ["-y", "mcp-remote", "https://api.sieutroly.ai/api/mcp", "--header", "Authorization:Bearer <API_KEY>"] } } }

Quyền → công cụ ​

Agent chỉ thấy công cụ mà scope của key cho phép (tools/list được lọc theo scope). Muốn agent chỉ xem dữ liệu thì tạo key chỉ có các quyền *:read.

Trần quyền khi tạo key: chỉ cấp được quyền ứng với quyền mà chính người tạo đang có trên web; không xoay, sửa hay xóa được key có quyền cao hơn mình. Chủ workspace không bị giới hạn.

ScopeCông cụ
(mọi key)whoami
orders:readlist_orders, get_order, get_order_settings, list_branches, search_address, list_shipping_providers, quote_shipping, get_shipment
orders:writecreate_order, update_order, set_order_status
orders:paymentset_order_payment, create_order_payment_qr
products:readlist_products, get_product, list_categories, list_stock, list_stock_movements
products:writecreate_product, update_product, create_category, update_category, stocktake
purchases:readlist_suppliers, get_supplier, list_banks, list_purchases, get_purchase, list_purchase_approvers
purchases:writecreate_supplier, update_supplier, pay_supplier, create_purchase, update_purchase, submit_purchase, withdraw_purchase, complete_purchase, cancel_purchase
customers:readsearch_customers, get_customer
customers:writecreate_customer, update_customer, add_customer_note
workflows:readlist_workflows, get_workflow, list_workflow_runs, get_workflow_run
content:readlist_content_accounts, list_content_posts, get_content_post, refresh_content_stats, get_content_analytics
content:writeimport_content_media, create_content_post, update_content_post, publish_content_post, delete_content_post — publish_content_post / publish_now đăng thật, công khai
workflows:runrun_workflow — chạy thật mọi bước (gửi tin, tạo đơn, gọi hệ thống ngoài…); chỉ cấp khi cần
shipping:writequote_order_shipping, ship_order, cancel_order_shipping, create_shipment, cancel_shipment — gọi tài xế thật qua Ahamove / AllinGo, phát sinh phí (get_shipment thuộc orders:read)
kiotviet:readlist_kiotviet_operations, kiotviet_read — đọc dữ liệu sống của cửa hàng KiotViet đã kết nối
kiotviet:writekiotviet_write — tạo/sửa/xóa thật trên KiotViet (hàng hóa, khách hàng, đặt hàng, hóa đơn, phiếu nhập/chuyển hàng)

Mỗi công cụ có annotations (readOnlyHint, destructiveHint) để client hỏi người dùng trước khi ghi. Máy chủ gửi kèm instructions hướng dẫn agent: tra product_id trước khi tạo đơn, tìm khách trước khi tạo mới để tránh trùng, v.v.

Quy tắc nghiệp vụ (giống API công khai) ​

  • Tiền là VND (số nguyên), thời gian ISO 8601.
  • Đơn hàng: giá lấy từ sản phẩm. Dòng tự nhập dùng name + unit_price. Muốn gọi lại an toàn thì truyền external_id: đã có đơn cùng mã thì hệ thống trả lại đơn cũ, không tạo đơn mới. Chỉ sửa được đơn còn ở trạng thái đầu.
  • Địa chỉ giao hàng: search_address (REST GET /places?q=, q ≥ 3 ký tự) gợi ý địa chỉ đầy đủ kèm toạ độ bằng bản đồ Ahamove; chỉ chạy khi workspace có kênh Ahamove đang hoạt động, không thì lỗi 409 ahamove_not_connected. Dùng label làm delivery_address.
  • Phí ship: quote_shipping (REST POST /shipping/quote) hỏi giá mọi kênh Ahamove / AllinGo đang hoạt động phục vụ chi nhánh (hoặc chỉ provider / channel_id), trả quotes theo giá tăng dần (hãng, dịch vụ, fee, eta, kênh) + cheapest; kênh lỗi nằm ở channels[].error, không chặn kênh khác. Truyền order để lấy địa chỉ, SĐT, chi nhánh và tiền thu hộ (phần chưa thanh toán) từ đơn. Điểm lấy hàng là chi nhánh (branch_id, trống = chi nhánh mặc định); chi nhánh thiếu địa chỉ/SĐT thì dùng điểm lấy hàng của kênh. Chưa có SĐT người nhận thì dùng SĐT chi nhánh (chỉ để báo giá). Chỉ báo giá, không tạo đơn giao và không ghi vào đơn — muốn tính vào đơn thì điền delivery_fee khi tạo/sửa đơn. Chưa có kênh giao hàng → 409 shipping_disabled. list_shipping_providers (GET /shipping/options) liệt kê các kênh.
  • Gọi giao hàng (scope shipping:write, dùng chính kênh Ahamove / AllinGo đã kết nối):
    • Cho đơn có sẵn (giống nút «Giao hàng» trên web): quote_order_shipping (REST POST /orders/{ref}/shipping/quote) báo giá từ kênh phục vụ chi nhánh của đơn (nhiều kênh thì truyền channel_id), địa chỉ/SĐT mặc định lấy từ đơn, báo giá được GIỮ 15 phút trong đơn → ship_order (POST /orders/{ref}/shipping, quote_id) tạo đơn giao thật, đơn chuyển «Đang giao», mã vận đơn/link theo dõi ở get_order → shipping → cancel_order_shipping (POST /orders/{ref}/shipping/cancel). Đơn đã có đơn giao đang chạy → 409 already_shipping; báo giá hết hạn → 409 quote_expired.
    • Giao độc lập (không gắn đơn, như bước «Vận chuyển» của Quy trình): create_shipment (POST /shipping/shipments: dropoff {SĐT bắt buộc + địa chỉ hoặc lat/lng}, pickup riêng tuỳ chọn, service = id báo giá / từ khoá, trống = rẻ nhất, cod_amount) → get_shipment (GET /shipping/shipments/{external_id}, scope orders:read) → cancel_shipment (POST /shipping/shipments/{external_id}/cancel). Không lưu bản ghi trong SieuTroLy, có nhật ký thao tác (shipping.direct_create / direct_cancel).
    • Workspace có nhiều kênh giao hàng thì phải truyền channel_id (400 channel_required); chưa có kênh → 409 shipping_disabled.
  • KiotViet (scope kiotviet:read / kiotviet:write, dùng kênh KiotViet đã kết nối): cùng bộ thao tác với các bước «KiotViet» của Quy trình. list_kiotviet_operations (REST GET /kiotviet/operations) trả kênh KiotViet (channel_id, retailer, ready) + danh mục thao tác (operation, access read/write/any, params). Chạy bằng kiotviet_read / kiotviet_write (cùng REST POST /kiotviet/run { operation, params, channel_id }): quyền xét theo phương thức thật — GET cần kiotviet:read, POST/PUT/DELETE cần kiotviet:write; kiotviet_read gọi thao tác ghi → 403 write_operation. Ô *_json (vd items_json, extra_json) nhận luôn object/array. Thao tác request (gọi endpoint tuỳ chọn trong danh sách được phép) dùng được với cả hai. Đăng ký/xóa webhook KiotViet KHÔNG mở qua API (404 unknown_operation, đường dẫn /webhooks → 403 forbidden_operation) để key không trỏ được dữ liệu cửa hàng ra URL tuỳ ý. Mỗi lần ghi có nhật ký kiotviet.write. Kết quả là dữ liệu sống từ KiotViet (khác list_products đọc bản đồng bộ trong SieuTroLy).
  • Sản phẩm, danh mục: chỉ bản ghi tự tạo (editable: true) sửa được mọi trường. Bản đồng bộ từ KiotViet hoặc Pancake chỉ đổi được is_active, cost_price, min_stock, supplier, kind. Đổi trường khác sẽ trả lỗi synced_product. Danh mục có tối đa 2 cấp.
  • Nguyên vật liệu, tồn kho: nguyên vật liệu là sản phẩm kind: "material" (list_products / list_stock lọc kind). list_stock trả tồn theo sản phẩm × chi nhánh: qty, reserved (giữ cho đơn chưa hoàn thành), available, status out/low/ok.
  • Kiểm kê: stocktake (REST POST /stock/stocktake, scope products:write) nhận branch_id + items: [{ product_id | sku, counted }] (≤ 200): tồn của chi nhánh được đặt đúng bằng counted, chênh lệch ghi thẻ kho loại stocktake, giá vốn không đổi, có nhật ký thao tác. dry_run: true chỉ trả before / counted / diff từng dòng, không ghi — agent nên xem trước rồi xác nhận với người dùng.
  • Phiếu nhập: create_purchase mặc định lưu nháp (chưa cộng kho); tiền do hệ thống tính (tổng tiền hàng − giảm giá + VAT + chi phí nhập = cần trả NCC; − paid = công nợ). Hoàn thành = cộng kho (giá vốn bình quân gia quyền) + ghi công nợ NCC; còn nợ thì bắt buộc supplier_id. Phiếu có approvers chỉ gửi duyệt được (submit_purchase; hoàn thành → approval_required). API key không phải người dùng nên không bao giờ duyệt/không duyệt được — người duyệt xử lý trên web/app. Phiếu chờ duyệt phải withdraw_purchase mới sửa được. cancel_purchase chỉ cho phiếu đã hoàn thành chưa trả nợ (trừ lại kho). pay_supplier chỉ GHI NHẬN khoản đã trả (không chuyển tiền), phân bổ phiếu cũ nhất trước.
  • Khách hàng: tạo khách trùng số điện thoại (mọi dạng 09…/+84…) trả lỗi duplicate_phone, kèm customer_id của khách đã có.
  • Quy trình: chỉ chạy được quy trình runnable: true, tức có Trigger «Chạy thủ công» (nhận input) hoặc hẹn giờ (chạy ngay, không nhận input). Quy trình chạy theo sự kiện (tiền vào SePay/Casso, đơn hàng, tin nhắn) bị từ chối với lỗi event_workflow, để không ai giả được sự kiện, ví dụ một giao dịch tiền vào bịa. run_workflow trả về lần chạy ở trạng thái queued/running; xem kết quả bằng get_workflow_run.
  • Đăng bài đa nền tảng: list_content_accounts trả các kênh đăng đang hoạt động (platform facebook = Facebook Page qua kênh «Facebook Video», youtube, tiktok_video = TikTok API chính thức, tiktok = TikTok cá nhân). Mỗi bài có targets[], mỗi kênh một nội dung riêng (caption, title, tuỳ chọn YouTube/TikTok), và media dùng chung: nhiều ảnh (≤10) HOẶC đúng 1 video. YouTube và TikTok chỉ nhận video. Media phải nằm trong kho keep/ của chính workspace: import_content_media tải từ URL https công khai (chặn địa chỉ nội bộ, không theo chuyển hướng, chỉ image/*/video/*, video ≤100MB, tính vào dung lượng gói); REST còn có POST /content/media/presign để tự PUT. URL ngoài hoặc tệp tmp/ bị từ chối. create_content_post không có scheduled_at = nháp; có = hẹn giờ. «Đăng ngay» (publish_content_post hoặc publish_now: true) không chờ upload: bài chuyển scheduled lúc đó, scheduler đăng trong ~20 giây, xem kết quả từng nền tảng (status, remote_url, error, warning) bằng get_content_post. Bài failed/partial đăng lại chỉ các nền tảng chưa thành công. Chỉ sửa/xóa được bài nháp/hẹn giờ; xóa không gỡ bài trên nền tảng.
  • Lỗi: công cụ trả isError: true kèm { code, message }, cùng mã lỗi với API công khai: invalid_request, not_found, insufficient_scope, rate_limited…
  • Giới hạn: mỗi lần gọi công cụ tính là một yêu cầu trong rate_limit_per_min của key. Riêng cửa /api/mcp có hạn mức thứ hai, gấp 5 lần hạn mức của key, đếm mọi yêu cầu kể cả initialize và tools/list. Vượt hạn mức trả 429.
  • Nhật ký: mọi thay đổi ghi người thực hiện là apikey:<id> và phát webhook như khi gọi REST.

Endpoint REST tương ứng ​

Mỗi công cụ MCP gọi lại API công khai v1 bằng chính key đó, nên dữ liệu, quyền, giới hạn tần suất, nhật ký và webhook giống hệt khi gọi REST. Đối tác không dùng MCP gọi thẳng các endpoint:

  • Sản phẩm: GET/POST /products, GET/PATCH /products/{id}
  • Danh mục: GET/POST /categories, PATCH /categories/{id}
  • Khách hàng:
    • GET /customers?q=, GET /customers/{id}
    • POST /customers, PATCH /customers/{id}
    • POST /customers/{id}/notes
  • Tồn kho: GET /stock, GET /stock/movements
  • Nhà cung cấp: GET/POST /suppliers, GET/PATCH /suppliers/{id}, POST /suppliers/{id}/payments, GET /banks
  • Phiếu nhập: GET/POST /purchases, GET /purchases/approvers, GET/PATCH /purchases/{id}, POST /purchases/{id}/submit|withdraw|complete|cancel
  • Quy trình:
    • GET /workflows, GET /workflows/{id}, GET /workflows/{id}/runs
    • POST /workflows/{id}/run, GET /workflow-runs/{id}

Lưu ý an toàn khi cho AI agent dùng ​

  • Chỉ dẫn độc trong dữ liệu (prompt injection): tên khách, ghi chú, nội dung đơn là dữ liệu do khách nhập, và agent đọc được. Nên dùng key chỉ có quyền đọc khi không cần ghi, và để client hỏi xác nhận trước khi dùng công cụ ghi (readOnlyHint: false, run_workflow có destructiveHint: true).
  • Ghi chú nội bộ: get_customer trả cả lịch sử ghi chú nội bộ của khách cho key có customers:read.

Hỗ trợ: contact@sieutroly.ai