Skip to main content
Glama
chris-youngblut-solutions

retail-ops-mcp-kit

retail-ops-mcp-kit

Four small Python MCP servers — one per enterprise-system class a retail/CPG operations agent integrates (ERP / supplier network / email / spreadsheet). Each server models a real named SaaS on the wire (SAP S/4HANA, SPS Commerce, Microsoft Graph, Google Sheets, …), selectable by env, over one shared synthetic corpus. Every mutation is a staged write: it validates, records a pending_approval record, returns an approval_id, and never executes. A separate approve(approval_id, token) needs a human token that lives only in the server environment and that the agent cannot read — so auto-execution is impossible by construction. Humans stay in control of what runs versus what waits, designed into the connector layer.

  • 4 servers, one runtime dependency (mcp>=1.27.2); everything else is stdlib.

  • FastMCP + hatchling src-layout + uv, Python 3.12, docstring-per-tool.

  • All data is fully synthetic and methodology-only — see PROVENANCE.md.

"I know your stack" — tool → real SaaS endpoint

Each server's tool signature is identical across every dialect it models; only the wire envelope changes (the connector seam). A host cannot tell which system answered.

retail-erp-mcp — the three-way match (PO / goods-receipt / invoice)

MCP tool

Kind

SAP S/4HANA (default)

Oracle NetSuite

MS Dynamics 365 F&O

get_purchase_order

read

GET …/API_PURCHASEORDER_PROCESS_SRV/A_PurchaseOrder('…')?$expand=to_PurchaseOrderItem{"d":{…}}

GET /services/rest/record/v1/purchaseOrder/{id}{id,tranId,entity,item:{items[]}}

GET /data/PurchaseOrderHeadersV2(dataAreaId='usmf',PurchaseOrderNumber='…'){@odata.etag,…}

get_goods_receipt

read

GET …/API_MATERIAL_DOCUMENT_SRV/A_MaterialDocumentHeader (GM type 101)

GET …/record/v1/itemReceipt/{id}

GET /data/ProductReceiptHeaders

get_invoice

read

GET …/API_SUPPLIERINVOICE_PROCESS_SRV/A_SupplierInvoice('…')

GET …/record/v1/vendorBill/{id}

GET /data/VendorInvoiceHeaders

list_open_pos

read

GET …/A_PurchaseOrder?$filter=…{"d":{"results":[]}}

GET …/record/v1/purchaseOrder?q=status:open{items,hasMore,offset}

GET /data/PurchaseOrderHeadersV2?$filter=PurchaseOrderStatus eq 'Backorder'

stage_invoice_payment

staged-write

POST …/API_JOURNALENTRYITEMBASIC_SRV/A_JournalEntryItemBasic (x-csrf-token)

POST …/record/v1/vendorPayment

POST /data/VendorPaymentJournalHeaders

stage_po_amendment

staged-write

PATCH …/A_PurchaseOrder('…') (If-Match / x-csrf)

PATCH …/record/v1/purchaseOrder/{id}

PATCH /data/PurchaseOrderHeadersV2(…) (If-Match etag)

simulate_po_event

webhook seam

Advanced Event Mesh CloudEvent sap/s4/beh/purchaseorder/v1/…/Created/v1

SuiteScript user-event https.post callback

Business Events → Azure Event Grid

Auth handshakes modeled per dialect (documented, never performed): SAP x-csrf-token: Fetch round-trip + sap-client; NetSuite OAuth1.0a account-ID host; D365 @odata.etag + If-Match.

retail-supplier-mcp — supplier network (ASNs / exceptions / deductions)

MCP tool

Kind

SPS Commerce (default)

Coupa

SAP Ariba

get_asn

read

EDI-856 Universal-JSON: hierarchicalLevels[] (S→O→T→I), carrier.scac, sscc18

REST ASN document

cXML ShipNoticeRequest

get_shipment_status

read

214-style status {shipmentIdentification, carrier, trackingNumber, status}

ASN status document

cXML StatusUpdateRequest

get_supplier

read

trading-partner {tradingPartnerId, senderId, …} (derived)

supplier record (derived)

supplier + NetworkID (derived)

list_exceptions

read

exception-queue rows [{id, po_id, evidence_text}] (gold_* withheld)

— same abstraction —

— same abstraction —

stage_credit_note

staged-write

EDI 810-variant

Coupa document-type:"credit_note"

InvoiceDetailRequest purpose="creditMemo"

stage_debit_note

staged-write

SPS debit doc

Coupa negative invoice

InvoiceDetailRequest purpose="debitMemo"

acknowledge_exception

staged-write

EDI 855 PO-ack (itemStatusCode IA/IB/IR) + 997 functional ack

POST /documents/{id}/acknowledge

cXML confirmation

simulate_inbound_asn

webhook seam

{eventType:"document.received", transactionType:"856", …} + the 856 payload

{event:"purchase_order.updated", …}

cXML StatusUpdateRequest

Ack/event vocabulary modeled: 850 (inbound PO), 856 (ASN), 810 (invoice), 855 (PO ack), 997 (functional ack); Coupa X-COUPA-API-KEY + scoped OAuth (core.invoice.write); Ariba dual apikey + OAuth and cXML <Credential domain="NetworkID">.

retail-email-mcp — supplier chase (mailbox threads + staged send)

MCP tool

Kind

Microsoft Graph (default)

Gmail API

list_chase_thread

read

GET /me/messages?$filter=conversationId eq '…'{"value":[…]}

GET /users/me/threads/{id}

get_supplier_reply

read

GET /me/messages/{id}

messages.get?format=full (base64url payload)

stage_chase_email

staged-write

POST /me/sendMail (202, no body)

messages.send {raw, threadId}

stage_escalation_email

staged-write

POST /me/sendMail with ccRecipients

messages.send {raw, threadId}

simulate_change_notification

webhook seam

Graph change-notification + validationToken echo

Pub/Sub {message:{data:<base64>}} + historyId cursor

The chase ladder tone (soft → firm → escalation) is recomputed from prior_chases against policy.chase_ladder — never read from a stored "next step".

retail-sheets-mcp — reconciliation worksheet

MCP tool

Kind

Google Sheets (default)

MS Graph Excel

read_reconciliation_sheet

read

GET /v4/spreadsheets/{id}/values/Reconciliation!A1:I11{range,majorDimension,values}

#microsoft.graph.workbookRange (values/text/numberFormat/valueTypes, JSON-number cells)

get_range

read

GET …/values/{range} over Reconciliation / Approvals / Audit

…/worksheets('…')/range(address='…')

stage_cell_update

staged-write

PUT …/values/{range}?valueInputOption=USER_ENTERED

PATCH …/range(address='…')

stage_row_append

staged-write

values:append

…/tables/{name}/rows/add {values:[[…]]}

simulate_change_notification

webhook seam

Drive files.watch push channel (Sheets values have no native webhook)

driveItem change-notification (+ 409/423 stale workbook-session)

Reconciliation is a PO+receipt+invoice+ASN join; Approvals (from approval_actions, with a recomputed Gated column) and Audit (from audit_entries, with a recomputed Complete column over policy.audit_required_fields) are also readable.

Related MCP server: fallpharm-mcp

The safety model — humans control what runs vs. what waits

  1. Every mutation is a staged write. A mutation tool validates its payload against the corpus, calls staging.stage(...), and returns {result:"pending_approval", approval_id, target_endpoint, payload, validation, status:"pending"}. Nothing executes at stage time.

  2. approve(approval_id, token) is the only path to execution, and it requires the human approval token from the server environment (RETAIL_OPS_MCP_APPROVAL_TOKEN). The supplied token is compared with hmac.compare_digest. That token is never a tool return, never in the corpus, never a default — the agent has no channel to read it, so any token it fabricates fails. Absent a configured token, approval fails closed (refused).

  3. Auto-execution is impossible by construction. Staging never executes; approve needs a secret the agent structurally cannot hold. This is the deliberate inverse of "no creds in argv": here the argv token is the human's proof-of-presence, intentionally withheld from the agent.

  4. Execution is fabrication, not persistence. On a valid human approval, the stored execute(payload) returns a synthetic SaaS response envelope (a SAP journal-entry doc number, a Graph 202, a Sheets updatedCells) recorded on the in-process ledger — it never appends to a JSONL or edits the corpus.

  5. A fingerprint invariant makes it testable. corpus.fingerprint() (sha256 over all fixture bytes) is byte-identical before staging, after staging, and after a full approve+execute. smoke_test.py asserts exactly this.

Shared on every server: approve, list_pending_approvals, get_approval_status, and an active_system() tell.

System selection

Each server picks the modeled SaaS dialect from an env var (validated allowlist, safe local default, no credentials):

Server

Env var

Allowlist

Default

retail-erp-mcp

RETAIL_ERP_SYSTEM

sap_s4hana, netsuite, dynamics365

sap_s4hana

retail-supplier-mcp

RETAIL_SUPPLIER_SYSTEM

sps_commerce, coupa, ariba

sps_commerce

retail-email-mcp

RETAIL_EMAIL_SYSTEM

msgraph, gmail

msgraph

retail-sheets-mcp

RETAIL_SHEETS_SYSTEM

google_sheets, msgraph_excel

google_sheets

active_system() reports the wired dialect without leaking any credential.

Data posture

All 11 fixtures are fully synthetic, methodology-only, and vendored verbatim from the agentic-eval-harness retail_ops set — see PROVENANCE.md. policy.json numbers are <<TOKEN>>-tagged invented placeholders; exception rows carry only abstract MARKER_* tokens in benign filler. The suppliers() resource is the one kit-authored derivation (synthesized from the supplier FK, flagged _derived). No network call is ever made; there is no runtime path back to the harness.

Develop

just setup       # uv sync --extra dev
just check       # lint + typecheck + test + smoke  (the gate)
just smoke       # dependency-light staged-write proof → prints SMOKE OK
just run-erp     # run a server on stdio (RETAIL_ERP_SYSTEM overridable)

Wire into an MCP host

Claude Desktop (claude_desktop_config.json) or a project .mcp.json:

{
  "mcpServers": {
    "retail-erp":      { "command": "uv", "args": ["run", "retail-erp-mcp"],
                         "env": { "RETAIL_ERP_SYSTEM": "sap_s4hana",
                                  "RETAIL_OPS_MCP_APPROVAL_TOKEN": "<operator-injected; NOT known to the agent>" } },
    "retail-supplier": { "command": "uv", "args": ["run", "retail-supplier-mcp"],
                         "env": { "RETAIL_SUPPLIER_SYSTEM": "sps_commerce",
                                  "RETAIL_OPS_MCP_APPROVAL_TOKEN": "<operator-injected>" } },
    "retail-email":    { "command": "uv", "args": ["run", "retail-email-mcp"],
                         "env": { "RETAIL_EMAIL_SYSTEM": "msgraph",
                                  "RETAIL_OPS_MCP_APPROVAL_TOKEN": "<operator-injected>" } },
    "retail-sheets":   { "command": "uv", "args": ["run", "retail-sheets-mcp"],
                         "env": { "RETAIL_SHEETS_SYSTEM": "google_sheets",
                                  "RETAIL_OPS_MCP_APPROVAL_TOKEN": "<operator-injected>" } }
  }
}

The approval token belongs in the host/operator's env injection (or a secrets manager), and is deliberately withheld from the agent — that withholding is the entire control. Without it configured, all approvals fail closed.

License

Dual-licensed under Apache-2.0 OR MIT (added at T1). All data synthetic — see PROVENANCE.md.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    C
    maintenance
    Enterprise-grade MCP server with multi-agent system for business AI transformation across finance, healthcare, retail, and other domains. Provides specialized AI agents for data analysis, API execution, business validation, and report generation with real-time monitoring and observability.
  • A
    license
    -
    quality
    C
    maintenance
    Provides a sovereign, MIT-licensed MCP server for professional-service workflows, running entirely on your infrastructure with Ed25519 cryptographic signing for every action.
    MIT
  • A
    license
    -
    quality
    B
    maintenance
    An MCP server that automates B2B deal matching: publish supply/demand, AI-driven cruise matching, and agent-based negotiation, with real-time notifications and reputation tracking.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for deterministic numeric verification and spreadsheet auditing. Enables AI agents to verify math/finance claims, audit rows, and evaluate covenant rules with signed, independently checkable receipts.
    4
    MIT

View all related MCP servers

Related MCP Connectors

  • Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.

  • Hosted MCP server for Mini Accountant: invoices, expenses, customers, analytics, tax estimates.

  • Remote MCP for Universal Cart merchant readiness MCP, structured receipts, audit logs, and reviewer-

View all MCP Connectors

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/chris-youngblut-solutions/retail-ops-mcp-kit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server