ops-mcp
Click on "Deploy 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., "@ops-mcpOrder A1023 was charged but failed. Investigate and recommend action."
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.
ops-mcp
A remotely-hosted MCP server that lets a non-technical operations user resolve a specific, common commerce-ops ticket end-to-end through an AI agent, instead of escalating to an engineer.
The workflow this covers
"Customer says they were charged but the order shows as failed."
Root cause: payment was captured, but the inventory hold expired before the order could be confirmed. The agent:
Investigates via read-only tools (order, payment, inventory hold, stock).
Diagnoses the mismatch and checks current stock.
Recommends one of two resolutions:
Stock available -> reconfirm the order (re-reserve stock, move to confirmed).
Stock unavailable -> issue a refund.
Waits for the operator to explicitly approve.
Executes the approved action via a write tool.
Verifies the outcome (checks shipment status after a reconfirm) before reporting success back to the operator.
Out of scope (deliberate): fulfillment/tracking mismatches, returns, fraud review, catalog/pricing issues, multi-item orders, and full inventory reconciliation across warehouses. These are structurally similar problems we'd extend to next using the same investigate -> recommend -> approve -> execute pattern.
Related MCP server: ecom-mcp
Architecture
AI agent (MCP client)
│ MCP over Streamable HTTP (stateless)
▼
Express server (src/server.ts)
│ registers 7 tools via @modelcontextprotocol/sdk McpServer
▼
Tool definitions (src/tools/definitions.ts)
│ each tool: name, AI-facing description, zod input shape, handler
▼
Data access layer (src/db/queries.ts) — OpsRepository class (all SQL lives here)
▼
Hosted PostgreSQL (Supabase)All state lives in the Postgres database, and the MCP transport is stateless —
a fresh McpServer + transport per request. This keeps hosting simple (no
sticky sessions needed) with no downside, since there is no server-side
session state to preserve.
Data
Hosted PostgreSQL, seeded once via npm run seed. Set the DATABASE_URL
environment variable (see .env.example) to point at your Postgres instance
(e.g. Supabase, Neon, or a local Docker container). The schema is defined in
src/db/schema.sql; seed data lives in src/db/seed.ts and uses
INSERT ... ON CONFLICT DO NOTHING for idempotent re-seeding. 10 orders
are seeded, covering: normal happy-path orders, the two core scenario
orders (A1023 = reconfirm path, A1024 = refund path), and three deliberate
edge cases (an already-refunded order, a cancelled order, and a "decoy"
order that looks similar but isn't actually broken).
Supabase pooler: If your DB host only has IPv6 DNS (Supabase's direct
db.[ref].supabase.coendpoint), use the Supabase Connection Pooler endpoint instead — it resolves to IPv4 and works from any hosting environment. Get it from the Supabase dashboard under Database → Connection Pooling. Format:postgresql://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres
MCP tools
Read (freely callable, no side effects):
get_order_detailsget_payment_statusget_inventory_hold_statuscheck_stock_availabilityget_shipment_status
Write (require an explicit confirmed_by_operator: true flag, only to be
set once a human has approved the specific action):
reconfirm_orderissue_refund
Write-tool safety guarantees
Explicit operator approval — both write tools require
confirmed_by_operator: true, set only after a human approves the specific action.Idempotent replay — both write tools require an agent-generated UUID
idempotency_key. Retrying with the same key replays the stored result instead of re-executing — including when two calls carrying that key arrive at genuinely the same instant, which a transaction-scoped advisory lock on the key serializes.Transactional audit + idempotency — the
action_logrow andidempotency_keysrow are committed in the same transaction as the mutation; they commit or roll back together.Oversell protection — stock decrement is a single atomic conditional
UPDATE ... WHERE available_qty >= $N; insufficient stock aborts and rolls back.Concurrent-write guards — every consequential
UPDATEre-checks its precondition in theWHEREclause at write time; 0 affected rows aborts the transaction with an actionable error telling the operator to re-investigate before acting.Refund releases inventory —
issue_refundreleases anystatus = 'active'hold on the order and credits the units back toavailable_qty, in the same transaction as the refund. No phantom reservations standing after a refund.
Write-tool rejection paths (refunded order, no captured payment, order not failed)
are logged but intentionally stand alone, since there's no mutation to share a transaction with.
Full tool descriptions (including preconditions and safety notes fed to
the calling model) are in src/tools/definitions.ts.
Running locally
Set up your environment first:
cp .env.example .env
# Edit .env to add your DATABASE_URL pointing at a PostgreSQL instance
# Load it: `export $(cat .env | xargs)` or use a .env loader
npm run seed # one-time: creates tables and inserts seed dataDefault (no flags): seed data is inserted with ON CONFLICT DO NOTHING —
safe to re-run on a live database; it will not overwrite or undo mutations
an agent may have made (e.g. an order reconfirmed from failed to confirmed
stays confirmed).
To reset demo/business state (truncate business tables and re-seed from scratch, preserving the audit log):
npm run seed -- --resetThe --reset flag truncates inventory_stock, inventory_holds, shipments,
payments, and orders (resetting all business state to clean demo data) plus
idempotency_keys (meaningless without their associated mutations). The
action_log audit trail is intentionally preserved — it is a durable
historical record by design, and should survive a business-state reset.
Then:
npm install
npm run dev # starts the MCP server on :3000 with tsx (no build step)Health check: GET http://localhost:3000/health
MCP endpoint: POST http://localhost:3000/mcp
Running the tests
Tests run against a real PostgreSQL instance, in a dedicated schema that the harness drops and recreates on every run:
npm test # 54 checks: tools, safety rejections, audit,
# idempotency, concurrency guards, inventory release
npm run test:concurrency # 26 checks: genuinely simultaneous write attempts,
# including same-key replay under real contention
npm run test:all # both suitesBoth suites call the tool handlers directly, so neither crosses the wire. For
protocol-level coverage — Express routing, McpServer registration, and the
Streamable HTTP transport — run the smoke script against a live server:
node scripts/mcp-smoke.mjs # localhost:3000
node scripts/mcp-smoke.mjs https://ops-mcp.onrender.com/mcp # deployedIt uses the official MCP SDK client, so it fails on what a real client would trip over. Read-only — it never calls a write tool, so it is safe against a live deployment.
Set TEST_DATABASE_URL to point at a Postgres instance; if unset, tests fall
back to DATABASE_URL. Either way the harness pins its connections to a
dedicated schema (TEST_SCHEMA, default ops_mcp_test), so business data in
public is never touched by a test run — including a run that fails partway
and leaves rows half-mutated.
src/tests/tools.test.ts calls the tool handlers directly (bypassing the
HTTP/MCP transport) and covers both resolution paths, every safety rejection,
transactional rollback, and the conditional-write guards.
src/tests/concurrency.test.ts fires simultaneous calls at the same order and
asserts exactly one succeeds.
Why not an in-memory mock? The suite previously ran against
pg-mem, which was found to acceptBEGIN/ROLLBACKwithout actually rolling back, and has no row-level locking. Both properties are exactly what the write-path guards depend on, so every abort-path assertion was passing without verifying anything. Seedocs/handoff.mdAppendix A.3.
Building for deployment
npm run build
npm start # runs dist/server.js, respects $PORTRemember to set DATABASE_URL in your deployment environment.
Platform notes:
Render / Railway / Fly / Heroku — Ideal. These run a persistent process; just set
DATABASE_URL(to the Supabase pooler connection string) and deploy. These are recommended.Vercel — Not recommended. Vercel uses serverless functions with cold starts and timeouts (10–15s). MCP over Streamable HTTP works but will be unreliable for longer-running operations. Use Render or Railway instead.
Render free-tier cold start: the deployed instance sleeps after ~15 min
idle; the first request after a gap can take 30-50s. Mitigate with a periodic
keep-warm ping (e.g. a cron job hitting /health).
Connecting an MCP client
The server is publicly deployed at https://ops-mcp.onrender.com/mcp. Point any
MCP-over-HTTP client (Streamable HTTP transport, stateless mode) at that URL —
or at POST /mcp on your own deployed instance.
OpenCode
OpenCode discovers MCP servers from the mcpServers field in your
.opencode/mcp.json in the project root (already configured here), or a
~/.opencode.json.
{
"mcpServers": {
"ops-mcp": {
"url": "https://ops-mcp.onrender.com/mcp"
}
}
}In a conversation, invoke the agent directly on an order:
/opencode ops-mcp help me with order A1023 — customer says they were charged but the order failedOpenCode will start a session with the MCP tools registered. No extra configuration needed beyond the JSON snippet above.
Claude Code
Claude Code reads MCP server config from the Claude Desktop config file
(claude_desktop_config.json on macOS/Windows, ~/.config/Claude/claude_desktop_config.json
on Linux) or from a local .mcp.json in the project root (Claude Code 1.95+).
Remote (Streamable HTTP) — use the public deployed server:
{
"mcpServers": {
"ops-mcp": {
"url": "https://ops-mcp.onrender.com/mcp",
"transport": "httpStream"
}
}
}Local .mcp.json (if you want to run the server yourself for per-project
scoping or development):
{
"mcpServers": {
"ops-mcp": {
"command": "node",
"args": ["dist/server.js"],
"env": {
"DATABASE_URL": "postgresql://..."
},
"transport": "stdio"
}
}
}Then in Claude Code, run:
/opencode ops-mcp investigate order A1023or simply mention the tools in a normal prompt — Claude Code will discover and call them automatically.
Codex
Codex reads MCP config from ~/.codex/mcp.json or .codex/mcp.json in
the project root.
Remote (Streamable HTTP) — use the public deployed server:
{
"mcpServers": {
"ops-mcp": {
"url": "https://ops-mcp.onrender.com/mcp"
}
}
}Local stdio (if you want to run the server yourself):
{
"mcpServers": {
"ops-mcp": {
"command": "node",
"args": ["/abs/path/to/ops-mcp/dist/server.js"],
"env": {
"DATABASE_URL": "postgresql://..."
},
"transport": "stdio"
}
}
}Then in a Codex task prompt:
Use the ops-mcp server to investigate order A1023: a customer says they were
charged but the order shows as failed. Check order details, payment status,
inventory hold, and stock. Recommend a resolution and wait for approval.Codex will auto-discover the registered MCP tools and use them.
License
MIT License with a commercial attribution clause — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Unified MCP server for 70+ eCommerce platforms: products, orders, customers, and more.
A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceA remotely hosted MCP server that lets ops personnel investigate and resolve inventory oversells without engineer involvement.-
- FlicenseNot gradedqualityBmaintenanceAn MCP server for e-commerce operations that enables AI agents to investigate stuck orders, surface fulfillment anomalies, and create escalation records via natural language queries.-
- FlicenseNot gradedqualityBmaintenanceMCP server that helps commerce operations investigate and safely recover orders left inconsistent after captured-payment webhook failures, with atomic recovery actions and audit history.-
- FlicenseNot gradedqualityBmaintenanceAn MCP server that enables operations teams to diagnose and recover stalled fulfillment orders via tools like retry_fulfillment and escalate_order, with safety boundaries limiting writes to retry and audit operations.-