Skip to main content
Glama

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:

  1. Investigates via read-only tools (order, payment, inventory hold, stock).

  2. Diagnoses the mismatch and checks current stock.

  3. Recommends one of two resolutions:

    • Stock available -> reconfirm the order (re-reserve stock, move to confirmed).

    • Stock unavailable -> issue a refund.

  4. Waits for the operator to explicitly approve.

  5. Executes the approved action via a write tool.

  6. 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.co endpoint), 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_details

  • get_payment_status

  • get_inventory_hold_status

  • check_stock_availability

  • get_shipment_status

Write (require an explicit confirmed_by_operator: true flag, only to be set once a human has approved the specific action):

  • reconfirm_order

  • issue_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_log row and idempotency_keys row 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 UPDATE re-checks its precondition in the WHERE clause at write time; 0 affected rows aborts the transaction with an actionable error telling the operator to re-investigate before acting.

  • Refund releases inventoryissue_refund releases any status = 'active' hold on the order and credits the units back to available_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 data

Default (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 -- --reset

The --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 suites

Both 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  # deployed

It 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 accept BEGIN/ROLLBACK without 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. See docs/handoff.md Appendix A.3.

Building for deployment

npm run build
npm start          # runs dist/server.js, respects $PORT

Remember 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 failed

OpenCode 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 A1023

or 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.

F
license - not found
Not graded
quality - not tested
B
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
    Not graded
    quality
    B
    maintenance
    A remotely hosted MCP server that lets ops personnel investigate and resolve inventory oversells without engineer involvement.
  • F
    license
    Not graded
    quality
    B
    maintenance
    An 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.
  • F
    license
    Not graded
    quality
    B
    maintenance
    An 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.

View all related MCP servers

Related MCP Connectors

  • 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 agents to onboard, pay, and provision services autonomously with InFlow

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/Yuvraj-ai/ops-mcp'

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