OHMS - Order Hub Management System
Flauraly Flowers and Plants - Python FastMCP server hosted on Replit Reserved VM.
Purpose
OHMS exposes a small, hardened set of order- and inventory-related tools to Violet (and any other authorized MCP client) over the Model Context Protocol. It centralizes Shopify Admin REST access behind a Bearer-auth gate so agents never touch raw Shopify credentials.
Architecture
+-----------------+ Bearer +------------------------------+
| MCP Client | ---------------> | OHMS (Replit Reserved VM) |
| (Violet, etc.) | /mcp or /sse | |
+-----------------+ | Starlette parent app |
| +-- /health (open) |
| +-- /mcp (Streamable HTTP)|
| +-- /sse (SSE fallback) |
| +-- BearerAuthMiddleware |
+--------------+---------------+
|
v
+------------------------------+
| Shopify Admin REST API |
+------------------------------+
Both /mcp (Streamable HTTP) and /sse (Server-Sent Events fallback) are
mounted simultaneously so any MCP client transport profile works.
Environment Variables
OHMS authenticates to Shopify via the OAuth 2.0 client_credentials grant.
The server never holds a long-lived SHOPIFY_ACCESS_TOKEN; instead it holds a
SHOPIFY_CLIENT_ID + SHOPIFY_CLIENT_SECRET pair and mints a short-lived
access token on demand against https://{shop}.myshopify.com/admin/oauth/access_token.
The minted token is cached in-memory with a 5-minute clock-skew buffer and
re-minted automatically (or on a 401/403 from any subsequent call). All values
are read via os.environ.get(...). Nothing is hardcoded.
| Var | Purpose |
|---|---|
PORT | TCP port to bind (Replit injects this; defaults to 8080). |
OHMS_API_TOKEN | Static bearer token required on every non-/health request (client to OHMS auth - separate from Shopify). |
SHOPIFY_STORE_URL | Shop domain, e.g. flauraly.myshopify.com. |
SHOPIFY_CLIENT_ID | Shopify app client ID (used for OAuth client_credentials grant). |
SHOPIFY_CLIENT_SECRET | Shopify app client secret (used for OAuth client_credentials grant). Rotate per Secrets_Registry.md schedule. |
SHOPIFY_API_VERSION | Pinned Shopify API version, e.g. 2025-01. |
PRINTER_IP | Local network IP of the receipt printer (stub uses this). |
See .env.example for the placeholder template.
Local Dev (Windows)
OHMS reads .env only when running locally (via python-dotenv). Bootstrap
your .env from the Windows DPAPI-protected secrets store rather than typing
secrets in plaintext:
# 1. Pull each secret from DPAPI into the local .env (PowerShell pseudocode)
$secrets = @("OHMS_API_TOKEN","SHOPIFY_STORE_URL","SHOPIFY_CLIENT_ID","SHOPIFY_CLIENT_SECRET","SHOPIFY_API_VERSION","PRINTER_IP")
foreach ($k in $secrets) {
$v = Unprotect-DpapiSecret -Name $k # your local helper
Add-Content .env "$k=$v"
}
# 2. Run the server
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python main.py
The server listens on http://0.0.0.0:8080 by default. Probe with:
curl http://localhost:8080/health
# => OHMS OK
Replit Deploy
- Create a Replit project and import this folder.
- In the Secrets pane, set every variable from
.env.example(using the real values - never paste them into any committed file). - Confirm
.replitshowsdeploymentTarget = "reserved_vm"and port8080 -> 80. - Deploy. The public URL is
https://ohms-server.crashzero9.replit.app. - Verify both transports:
curl https://ohms-server.crashzero9.replit.app/health curl -H "Authorization: Bearer $OHMS_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \ https://ohms-server.crashzero9.replit.app/mcp
Tool Registry
| Tool | Source | Notes |
|---|---|---|
get_order(order_id) | Shopify Admin REST | GET /orders/{id}.json |
list_pending_orders() | Shopify Admin REST | GET /orders.json?status=open&limit=50 |
update_order_status(order_id, status) | Shopify Admin REST | PUT /orders/{id}.json (sets tags) |
get_inventory_snapshot() | Shopify Admin REST | GET /inventory_levels.json?limit=50 |
get_doordash_orders_via_browser() | Stub | Returns routing dict for browser-automation handoff. |
print_order_ticket(order_id) | Stub | Reads PRINTER_IP; returns queued status. Driver pending. |
Phase Status
- Phase 1 (current): MVP scaffold, Bearer auth, six tools (4 live + 2 stubs), Replit Reserved VM deploy, basic pytest suite.
- Phase 2 (planned): OAuth 2.1 replacing static bearer, full DoorDash driver, real network printer driver, structured logging with secret redaction, rate limiting.
Security Notes
- No secret values appear in any committed file.
Authorizationheaders and full Shopify response bodies are never logged./healthreturns only the literal stringOHMS OK- no version, env, or path info.- All
httpxcalls have an explicit 30-second timeout.