Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Sapo

FreeNot checked

Model Context Protocol server for Sapo.vn POS & e-commerce platform, providing 105 tools across 4 modes for managing orders, inventory, customers, and more.

GitHubEmbed

About

Model Context Protocol server for Sapo.vn POS & e-commerce platform, providing 105 tools across 4 modes for managing orders, inventory, customers, and more.

README

npm version License: MIT Node 20+

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 web
  • Two 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 require confirm: true
  • Single-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 --version

Option B — global install

npm install -g sapo-mcp
sapo-mcp --version
sapo-mcp --help

Option C — local project dependency

npm install sapo-mcp
npx sapo-mcp --mode=pos-online

Quick Start

1. Get Credentials

Create a Private App at developers.sapo.vn:

  • Store name: mystorenamemystorename.mysapo.net
  • API 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-online

Open 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
--mode=<modes> pos-online Comma-separated list of modes to activate
--transport=<t> stdio Transport type (stdio or http)
--port=<port> 3333 HTTP port (ignored for stdio)
--help Print usage and exit
--version Print version and exit

Environment Variables

Variable Required Default Description
SAPO_STORE Yes Store subdomain
SAPO_API_KEY Yes Private App API Key
SAPO_API_SECRET Yes* Private App API Secret
SAPO_API_SECRET_FILE Yes* Path to file containing secret (takes precedence)
SAPO_ALLOW_OPS No "" CSV of allowed destructive categories
SAPO_MAX_AUTO_PAGES No 10 Max auto-pagination pages
SAPO_RETRY_MAX No 3 HTTP retry attempts
SAPO_LOG_LEVEL No info Log level (error/warn/info/debug/trace)
SAPO_HTTP_HOST No† 127.0.0.1 HTTP bind host (loopback by default)
SAPO_HTTP_PORT No 3333 HTTP port
SAPO_HTTP_MAX_SESSIONS No 100 Max concurrent MCP sessions
SAPO_HTTP_SESSION_IDLE_MS No 1800000 Idle session GC threshold (30 min)
SAPO_MCP_AUTH_TOKEN No† Bearer token. Required if host is non-loopback
SAPO_HTTP_CORS_ORIGINS 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
pos-online 0.5.0 Online orders, customers, fulfillment (51 tools)
web 0.5.0 Storefront, collections, articles, SEO (31 tools)
pos-counter 0.5.0 POS counter: locations, inventory write, suppliers, shifts, stock transfers (15 tools)
analytics 0.5.0 Composed reports: revenue, top products/customers, LTV, tax, channel breakdown, discount usage, shift report (10 tools)

Note: pos-counter excludes 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 carry truncated: true when 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 .github/workflows/canary.yml
🟢 Live-verified Endpoint hit during development, schema captured to fixture, not in daily canary
🟡 Docs-only Schema from docs/sapo-api-reference.md (Sapo official); mock tests only, no live probe
🔵 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 /admin/store.json
products (read) pos-online, pos-counter /admin/products.json
orders pos-online, pos-counter /admin/orders.json
customers pos-online, pos-counter /admin/customers.json
inventory_levels pos-online, pos-counter /admin/inventory_levels.json
locations pos-counter /admin/locations.json
draft_orders pos-online /admin/draft_orders.json
price_rules pos-online /admin/price_rules.json
pages web /admin/pages.json
suppliers pos-counter /admin/suppliers.json
stock_transfers pos-counter /admin/stock_transfers.json
payment_methods pos-counter /admin/payment_methods.json

🚨 Broken — needs investigation

Tool Resource Issue
list_pos_shifts pos_shifts /admin/pos_shifts.json returns Content-Type: text/html (Sapo POS web app shell), not JSON.
get_pos_shift 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.

pos-online — 51 tools (with `SAPO_ALLOW_OPS=*`)

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)
web — 31 tools

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
pos-counter — 15 tools

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)
analytics — 10 tools

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-online

Supported 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 canary

Write-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=http

Endpoints:

Method Path Description
GET /health Liveness probe — returns { status, version, modes, sessions }
POST /mcp JSON-RPC over Streamable HTTP (creates a session on initialize)
GET /mcp SSE long-poll for an existing session (mcp-session-id header)
DELETE /mcp 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) requires SAPO_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:local

Development

npm install
npm run typecheck   # Type check
npm run lint        # Lint
npm run test        # Run tests
npm run build       # Build for release

Post-1.0 roadmap

The 1.0.0 stable cut is gated on the following items, deferred from this release:

  • MCP Resourcessapo://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-counter and 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

from github.com/nguyennguyenit/Sapo-MCP

Installing Sapo

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/nguyennguyenit/Sapo-MCP

FAQ

Is Sapo MCP free?

Yes, Sapo MCP is free — one-click install via Unyly at no cost.

Does Sapo need an API key?

No, Sapo runs without API keys or environment variables.

Is Sapo hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Sapo in Claude Desktop, Claude Code or Cursor?

Open Sapo on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Sapo with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All development MCPs