sapo-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sapo-mcpshow my recent orders"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
sapo-mcp
Model Context Protocol server for Sapo.vn POS & e-commerce platform.
Features
4 modes, 105 unique tools:
pos-online(51),web(31),pos-counter(15),analytics(10) — 2 read tools shared between pos-online and webTwo transports: stdio (Claude Desktop, Cursor) and Streamable HTTP (Docker, GoClaw)
Safe by default: destructive ops gated via
SAPO_ALLOW_OPS(default: none); all destructive calls also requireconfirm: trueSingle-tenant: one shop per server instance via Private App credentials
Pre-1.0: tool names and schemas may shift on minor bumps. See Post-1.0 roadmap.
Installation
Requires Node.js 20 or newer. Verify with node --version.
Option A — npx (no install)
Recommended for MCP clients (Claude Desktop, Cursor). Always pulls the latest published version:
npx -y sapo-mcp@latest --versionOption B — global install
npm install -g sapo-mcp
sapo-mcp --version
sapo-mcp --helpOption C — local project dependency
npm install sapo-mcp
npx sapo-mcp --mode=pos-onlineQuick Start
1. Get Credentials
Create a Private App at developers.sapo.vn:
Store name:
mystorename→mystorename.mysapo.netAPI Key + Secret
2. Configure your MCP client
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%/Claude/claude_desktop_config.json (Windows):
{
"mcpServers": {
"sapo": {
"command": "npx",
"args": ["-y", "sapo-mcp", "--mode=pos-online,web,analytics"],
"env": {
"SAPO_STORE": "mystorename",
"SAPO_API_KEY": "xxx",
"SAPO_API_SECRET": "yyy"
}
}
}
}Restart Claude Desktop. Tools appear under the 🔌 plug icon.
Cursor
Edit ~/.cursor/mcp.json or per-workspace .cursor/mcp.json:
{
"mcpServers": {
"sapo": {
"command": "npx",
"args": ["-y", "sapo-mcp", "--mode=pos-online,web"],
"env": {
"SAPO_STORE": "mystorename",
"SAPO_API_KEY": "xxx",
"SAPO_API_SECRET": "yyy"
}
}
}
}MCP Inspector (test/debug)
npx @modelcontextprotocol/inspector \
-e SAPO_STORE=mystorename \
-e SAPO_API_KEY=xxx \
-e SAPO_API_SECRET=yyy \
npx -y sapo-mcp --mode=pos-onlineOpen the printed URL in a browser to inspect/invoke registered tools.
Use --mode=pos-online,web,analytics to register multiple modes (union of tools; shared tools registered once).
3. CLI Flags
Flag | Default | Description |
|
| Comma-separated list of modes to activate |
|
| Transport type ( |
|
| HTTP port (ignored for stdio) |
| — | Print usage and exit |
| — | Print version and exit |
Environment Variables
Variable | Required | Default | Description |
| Yes | — | Store subdomain |
| Yes | — | Private App API Key |
| Yes* | — | Private App API Secret |
| Yes* | — | Path to file containing secret (takes precedence) |
| No |
| CSV of allowed destructive categories |
| No |
| Max auto-pagination pages |
| No |
| HTTP retry attempts |
| No |
| Log level (error/warn/info/debug/trace) |
| No† |
| HTTP bind host (loopback by default) |
| No |
| HTTP port |
| No |
| Max concurrent MCP sessions |
| No |
| Idle session GC threshold (30 min) |
| No† | — | Bearer token. Required if host is non-loopback |
| No | — | CSV of allowed CORS origins (default: disabled) |
*One of SAPO_API_SECRET or SAPO_API_SECRET_FILE is required.
†HTTP-only. Token is enforced when SAPO_HTTP_HOST is not 127.0.0.1/localhost/::1.
Modes
Mode | Status | Description |
| 0.5.0 | Online orders, customers, fulfillment (51 tools) |
| 0.5.0 | Storefront, collections, articles, SEO (31 tools) |
| 0.5.0 | POS counter: locations, inventory write, suppliers, shifts, stock transfers (15 tools) |
| 0.5.0 | Composed reports: revenue, top products/customers, LTV, tax, channel breakdown, discount usage, shift report (10 tools) |
Note:
pos-counterexcludes 5 internal-only endpoints (purchase_orders,purchase_returns,stock_adjustments,cash_transactions,cashbook) — these return HTTP 403 for Private App credentials and require an OAuth Partner App (post-1.0 roadmap).Analytics tools auto-paginate up to
SAPO_MAX_AUTO_PAGES; results carrytruncated: truewhen the cap is hit.
Tool Verification Status
Verification levels for the 105 unique tools (last updated 2026-04-30):
Symbol | Level | What it means |
✅ | Canary-monitored | Endpoint + schema verified live; daily nightly probe via |
🟢 | Live-verified | Endpoint hit during development, schema captured to fixture, not in daily canary |
🟡 | Docs-only | Schema from |
🔵 | Composed | Not a Sapo endpoint — internal aggregation logic, logic-tested via unit tests |
🚨 | Broken | Known non-functional, see notes |
Canary-monitored endpoints (drift detected within 24h)
Resource | Mode(s) | Endpoint |
store | all |
|
products (read) | pos-online, pos-counter |
|
orders | pos-online, pos-counter |
|
customers | pos-online, pos-counter |
|
inventory_levels | pos-online, pos-counter |
|
locations | pos-counter |
|
draft_orders | pos-online |
|
price_rules | pos-online |
|
pages | web |
|
suppliers | pos-counter |
|
stock_transfers | pos-counter |
|
payment_methods | pos-counter |
|
🚨 Broken — needs investigation
Tool | Resource | Issue |
| pos_shifts |
|
| pos_shifts | Same as above. JSON API endpoint not yet located. |
These 2 tools may fail at runtime. POS shift management currently requires admin UI.
Per-tool status
Click each section to expand the full tool list with status icons.
Customers (7)
✅
list_customers,get_customer,search_customers,count_customers,list_customer_orders🟢
create_customer,update_customer
Customer Addresses (4)
🟡
list_customer_addresses,add_customer_address,update_customer_address,set_default_customer_address
Products (read) (4)
✅
list_products,get_product,search_products,count_products
Variants (read) (2)
🟡
list_variants_for_product,get_variant
Inventory (read) (1)
✅
get_inventory_levels
Orders (4)
✅
list_orders,get_order,count_orders,search_orders
Order Transactions (2)
🟢
list_order_transactions,create_order_transaction
Fulfillments (4)
🟢
list_fulfillments_for_order,get_fulfillment🟡
create_fulfillment,update_fulfillment_tracking
Refunds (3)
🟢
list_refunds,get_refund,create_refund(create_refund destructive:SAPO_ALLOW_OPS=refund)
Draft Orders (7)
✅
list_draft_orders,get_draft_order🟡
create_draft_order,update_draft_order,complete_draft_order,send_draft_order_invoice,delete_draft_order(destructive:delete)
Price Rules (5)
✅
list_price_rules,get_price_rule🟡
create_price_rule,update_price_rule,delete_price_rule(destructive:delete)
Discount Codes (3)
🟡
list_discount_codes,create_discount_code,delete_discount_code(destructive:delete)
Destructive (cancel/delete-strict) (4)
🟡
cancel_order,close_order,cancel_fulfillment(destructive:cancel)🟡
delete_customer,delete_variant(destructive:delete_strict)
Store (1)
✅
get_store_info
Articles (5)
🟡
list_articles,get_article,create_article,update_article,delete_article(destructive:delete)
Blogs (5)
🟡
list_blogs,get_blog,create_blog,update_blog,delete_blog(destructive:delete)
Pages (4)
✅
list_pages,get_page🟡
update_page_seo,delete_page(destructive:delete)
Collections (10)
🟡
list_custom_collections,get_custom_collection,create_custom_collection,update_custom_collection,delete_custom_collection(destructive:delete)🟡
list_smart_collections,get_smart_collection🟡
list_collects,create_collect,delete_collect(destructive:delete)
Script Tags (3)
🟡
list_script_tags,create_script_tag,delete_script_tag(destructive:delete)
Products SEO (1)
🟡
update_product_seo
Variants (read, shared) (2)
🟡
list_variants_for_product,get_variant
Locations (2)
✅
list_locations,get_location
Payment Methods (1)
✅
list_payment_methods
Inventory (write) (3)
🟡
adjust_inventory_level,connect_inventory_level🟡
set_inventory_level(destructive:inventory_set)
Variants (write) (1)
🟡
update_variant
POS Orders (2)
✅
list_pos_orders,get_pos_order(uses/admin/orders?source_name=pos)
Suppliers (2)
✅
list_suppliers,get_supplier
Stock Transfers (2)
✅
list_stock_transfers,get_stock_transfer
POS Shifts (2)
🚨
list_pos_shifts,get_pos_shift(see Broken section above — endpoint returns HTML)
All 10 are 🔵 composed (aggregate from multiple Sapo endpoints, no single endpoint to verify):
revenue_summary, top_products, top_customers, customer_ltv, tax_summary, online_vs_counter_breakdown, discount_usage_report, shift_report, inventory_low_stock, inventory_value
Destructive Operations
Destructive tools (cancel, delete, bulk-delete) are blocked by default. To enable specific categories:
# Allow order cancellation and standard deletes only
SAPO_ALLOW_OPS=cancel,delete npx sapo-mcp --mode=pos-onlineSupported categories: cancel, delete, delete_strict, inventory_set, refund, shift_close, cashbook_write.
All destructive tool calls also require confirm: true in the tool arguments — this prevents accidental execution when an LLM calls the tool without explicit intent.
Security
ENV credentials are visible to other processes via ps / /proc/<pid>/environ on shared hosts. Use SAPO_API_SECRET_FILE to pass the secret via a file instead of an env var where possible.
Note: full secret-file isolation (reading the secret only at startup, then clearing) is tracked for the post-1.0 roadmap.
Probing
Verify which Sapo API endpoints are available on your store before configuring tools.
# Read-only probe — safe to run against any store (GET only)
SAPO_STORE=mystore SAPO_API_KEY=xxx SAPO_API_SECRET=yyy npm run probe
# Schema drift check — same probe + Zod validation against fixtures
npm run canaryWrite-probe (npm run probe:write) refuses to run unless SAPO_STORE contains test, dev, or sandbox — never against production.
HTTP Transport (Remote / Docker)
Run as an HTTP server for remote MCP clients (e.g. GoClaw) or self-hosted Docker:
# Local-only (no auth required)
sapo-mcp --mode=pos-online --transport=http --port=3333
# Public bind (auth token required)
SAPO_HTTP_HOST=0.0.0.0 \
SAPO_MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
sapo-mcp --mode=pos-online --transport=httpEndpoints:
Method | Path | Description |
|
| Liveness probe — returns |
|
| JSON-RPC over Streamable HTTP (creates a session on |
|
| SSE long-poll for an existing session ( |
|
| Terminate a session |
Session model: Each MCP client gets a UUID session, isolated by an
McpServer instance. Idle sessions (SAPO_HTTP_SESSION_IDLE_MS) are
evicted automatically. Concurrent sessions cap at SAPO_HTTP_MAX_SESSIONS
(503 returned when full).
Security:
Defaults to
127.0.0.1— loopback only. Token optional.Setting
SAPO_HTTP_HOST=0.0.0.0(or any non-loopback) requiresSAPO_MCP_AUTH_TOKEN. The server refuses to start otherwise.CORS is off by default. Enable per-origin via
SAPO_HTTP_CORS_ORIGINS(CSV of origins, or*for all). Only enable when serving browser-based agents.
Docker
See examples/Dockerfile and
examples/docker-compose.yml.
docker build -f examples/Dockerfile -t sapo-mcp:local .
docker run --rm -p 3333:3333 \
-e SAPO_STORE=mystore \
-e SAPO_API_KEY=xxx -e SAPO_API_SECRET=yyy \
-e SAPO_HTTP_HOST=0.0.0.0 \
-e SAPO_MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
sapo-mcp:localDevelopment
npm install
npm run typecheck # Type check
npm run lint # Lint
npm run test # Run tests
npm run build # Build for releasePost-1.0 roadmap
The 1.0.0 stable cut is gated on the following items, deferred from this release:
MCP Resources —
sapo://shop/info,sapo://orders/today,sapo://orders/pending,sapo://inventory/low-stock. Read-heavy data is more efficient as a Resource than repeated tool calls.MCP Prompts — templated workflows (
respond_to_complaint,weekly_report,seo_optimize_product,customer_followup).Webhook receiver — sub-package surfacing Sapo webhooks as MCP events.
OAuth 2.0 Partner App — multi-tenant SaaS deployments. Unlocks the 5 internal-only endpoints currently excluded from
pos-counterand 4 deferred finance/PO reports (cashflow_summary,pnl_summary,supplier_purchase_summary,daily_pos_report).Storefront GraphQL module — verify Private App access; scope tools if available.
Changelog
See CHANGELOG.md for the per-version history.
License
MIT — See LICENSE
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nguyennguyenit/Sapo-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server