sapo-mcp

sapo-mcp

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

Category
Visit Server

README

sapo-mcp

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.

<details> <summary><b>pos-online — 51 tools (with SAPO_ALLOW_OPS=*)</b></summary>

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)

</details>

<details> <summary><b>web — 31 tools</b></summary>

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

</details>

<details> <summary><b>pos-counter — 15 tools</b></summary>

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)

</details>

<details> <summary><b>analytics — 10 tools</b></summary>

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

</details>

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

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured