OpsDesk

OpsDesk

A remote MCP server that lets a commerce operations agent investigate and resolve stuck orders without escalating to engineering or needing database access. It diagnoses order issues, proposes safe remediations, and requires human confirmation before executing any changes.

Category
访问服务器

README

OpsDesk

A remote MCP server that lets a commerce operations agent investigate and resolve stuck orders — without escalating to engineering, and without being handed a database.

  • Hosted MCP endpoint: https://opsdesk-mcp.vercel.app/api/mcp
  • Health check: https://opsdesk-mcp.vercel.app/api/health
  • Source: https://github.com/katareayush/opdesk-mcp
  • Demo keys: demo-agent-key (ops agent), demo-manager-key (ops manager)

All data is synthetic. No real customers, no real payment data, no production credentials.

Reviewing this: the workflow · connect in one command · demo orders worth trying · MCP design decisions · safety model · scope and exclusions · limitations · AI worklog


The problem

When a customer writes "I paid three days ago and nothing has shipped", the answer lives in four systems: the order system knows what was bought, the payment processor knows whether money actually moved, the warehouse knows whether anyone was ever asked to pick it, and the carrier knows whether it left the building. No single one of them can tell you what went wrong.

So the ops agent escalates, and an engineer spends twenty minutes joining records by hand.

OpsDesk does that join server-side, names the failure, and offers only the fixes that are actually legal for that specific order — behind a confirmation step that a human has to pass.

The workflow

find_stuck_orders  →  investigate_order  →  propose_remediation  →  [human says yes]  →  execute_remediation
                                                        ↓
                                            escalate_to_engineering
  1. find_stuck_orders — ranked queue of what's actually broken, with money at risk and how long each customer has waited. Healthy orders are excluded by construction.
  2. investigate_order — one merged chronological timeline across all four systems, a diagnosed failure class with the evidence behind it, and an availability check on every remediation including why the unavailable ones are unavailable.
  3. propose_remediation — computes exactly what a fix would do (money, stock, resulting status, draft customer message) and issues a signed confirmation token. Changes nothing.
  4. execute_remediation — the only tool that mutates anything. Requires the token plus an idempotency key.
  5. escalate_to_engineering — packages the evidence bundle when nothing is legal or the diagnosis is UNKNOWN_STALL. Escalating well is a success path, not a failure.

Supporting: check_inventory (oversells and who's competing for the stock), get_audit_log (what was done, by whom, and what was refused).

Plus an MCP resource (opsdesk://runbook — the failure-class runbook and role limits) and a prompt (morning_triage).


Connect to it

Claude Code

claude mcp add --transport http opsdesk https://opsdesk-mcp.vercel.app/api/mcp \
  --header "Authorization: Bearer demo-agent-key"

Then try: "What orders are stuck right now?""What's wrong with ORD-1001?""Refund it."

To see the policy escalation path, reconnect with demo-manager-key and compare what each role is allowed to do to ORD-1013.

MCP Inspector (no project setup)

npx @modelcontextprotocol/inspector

Transport Streamable HTTP, URL https://opsdesk-mcp.vercel.app/api/mcp, and add header Authorization: Bearer demo-agent-key. Gives you a click-through view of every tool, its schema, and the runbook resource.

Raw HTTP

curl -s -X POST https://opsdesk-mcp.vercel.app/api/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Authorization: Bearer demo-agent-key' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"investigate_order","arguments":{"order_id":"ORD-1001"}}}'

Locally

npm install
npm test          # 54 tests
npm run typecheck
npm run dev       # vercel dev

Auth is header-only by design. I did not add a ?key= query-param fallback even though it would be marginally easier to paste around — keys in query strings end up in access logs and referrers, and a demo that models bad credential handling teaches the wrong thing.


Demo orders

Stable IDs, one per failure class, so the demo and the tests reference the same cases.

Order Diagnosis Why it's interesting
ORD-1001 PAYMENT_CAPTURED_NO_FULFILLMENT The hero case: paid 74h ago, warehouse never got it
ORD-1003 DUPLICATE_CHARGE Charged twice; server computes the refund, caller can't override it
ORD-1004 OVERSOLD_INVENTORY Retry is refused — stock is still zero, it would fail identically
ORD-1016 OVERSOLD_INVENTORY Same rejection, but stock arrived since, so retry is allowed
ORD-1007 ADDRESS_VALIDATION_FAILED Label failed as undeliverable → routed to the address class, not the carrier class
ORD-1009 PAYMENT_AUTHORIZED_NOT_CAPTURED Authorization expired; capture refused, release allowed
ORD-1011 UNKNOWN_STALL Doesn't match any rule — the system says so instead of guessing
ORD-1013 PAYMENT_CAPTURED_NO_FULFILLMENT $939 → agent gets requires_approval, manager gets ready
ORD-1014 PAYMENT_CAPTURED_NO_FULFILLMENT $3,490 → blocked for every ops role; that's a finance decision
ORD-1015 HEALTHY Delivered. Must never appear in the stuck queue

MCP design decisions

The server holds the judgement, not the model. Diagnosis is a pure function over the order bundle — a priority-ordered rule set, not a prompt. The model orchestrates and explains; it never decides what class of failure something is, and it cannot invent a remediation. If diagnosis were left to the model it would be non-deterministic, unreviewable, and untestable, and the class gate below would be built on sand.

A failure class is a gate, not a label. Each class declares which remediations are valid from it. retry_carrier_label is simply not reachable from ADDRESS_VALIDATION_FAILED, because retrying the label would fail in exactly the same way.

Legality is separate from policy. Is this action coherent for this order? and is this actor allowed to do it at this amount? are different questions with different answers. Keeping them apart is why a refund can be perfectly valid and still correctly refused for a junior agent — which is how a real back office works.

Every response carries the workflow forward. Tool results include a next_steps field. Refusals are structured data with reasons written for the ops person, not exceptions — so the model relays them instead of trying a different tool to get around them.

Unavailable options stay visible. investigate_order returns every remediation with available: true|false and, when false, unavailable_because. Hiding them would make the model retry blindly; showing the reason lets it explain the situation to the human.

Tool descriptions are written for the AI consumer. They say when to use the tool, when not to, and what the caller is expected to do next. The server also ships instructions on initialize that state the approval requirement explicitly.


Safety model

Assume the model in front of this server will sometimes be confused, and that a confused model with a refund tool is a financial incident.

Rail What it stops
Two-phase write Nothing that moves money or stock is reachable in one call. execute_remediation requires a token only the server can mint, and only after legality + policy pass.
HMAC-signed tokens A token can't be constructed or edited. Tampering with the order id inside it fails the signature check.
Precondition fingerprint The token is bound to the state the preview was computed against. If anything material changed in between, execution refuses rather than applying a stale plan. Irrelevant churn (an added note) deliberately does not invalidate it.
Single-use + 15m TTL A token leaked into a transcript can't be replayed later, and a token can't be used twice.
Actor binding A token issued to one user can't be executed by another. The approver has to get their own preview.
Idempotency keys Retry after a network error is safe; the original result replays and nothing is applied twice. Reusing a key for a different action is refused outright.
Re-validation at execute Legality and policy are re-run against live state at execution, not trusted from proposal time.
Role limits Per-action and per-day refund caps by role, evaluated against the audit log so caps can't be evaded by splitting one refund into many.
Transactional apply A failure mid-apply rolls back the whole change. "Money moved, stock didn't" is unreachable.
Append-only audit Refusals are recorded alongside successes — the record shows what was attempted, not just what worked.

Deliberately not automated: OpsDesk never contacts a customer. It drafts messages; a human sends them. It also never picks between competing orders for oversold stock — it surfaces the options and says that's a business decision.


Scope

In: one workflow (stuck-order triage → resolution), seven tools, nine remediations, ten failure classes, the full safety model above, hosted and tested.

Out, deliberately:

  • Frontend — the MCP client is the interface.
  • Real auth — bearer key → actor+role. It provides attribution and limits, which the safety model needs; SSO would change one file.
  • Real payment/carrier/WMS integrations — mocked as internal services with realistic failure codes. Wiring Stripe would prove integration skill, not product judgement, and the brief says use synthetic data.
  • A complete commerce backend — no cart, no checkout, no returns, no tax.
  • Multi-currency — USD only. Every money value is integer cents; the string fields are display-only.

Assumptions: one warehouse; refunds go to the original payment method; a 24h fulfillment SLA and a 7-day lost-parcel threshold (both configurable constants in diagnose.ts); ops staff are trustworthy but time-pressured — the rails are there to catch mistakes, not malice.


Limitations & next steps

State is in-memory and per-instance. This is the significant one. The dataset is seeded deterministically at cold start, so every instance begins identical, but writes are local to the instance that served them and are lost on cold start. Practical consequences:

  • A propose→execute pair that lands on two different instances returns unknown_proposal rather than doing something wrong — it fails safe, but it can fail. In practice consecutive calls hit the same warm instance; the deployed demo above works end to end.
  • Single-use token enforcement and idempotency are per-instance, not global.

Everything durable goes through the Database class, so the fix is one adapter (Postgres, with the proposal/idempotency/audit tables as the schema) rather than a refactor. I chose the demo being trivially runnable over the durability story, and I'd reverse that for anything real.

Other known gaps:

  • Refund caps are per-actor-per-day but not per-order — an actor could refund many different orders up to their daily cap. Intentional; a per-order cap belongs to a returns policy that doesn't exist here.
  • UNKNOWN_STALL is a catch-all. In production the rule set would grow from real incidents, and the escalation records are exactly the raw material for that.
  • The mock carrier is deterministic. Real transient failures would need retry/backoff semantics that this doesn't model.
  • No rate limiting on the endpoint, no pagination beyond limit caps.

Tests

npm test    # 54 tests, ~0.5s
  • diagnose.test.ts — every planted scenario pinned to its expected class, plus the judgement calls (undeliverable label → address class, duplicate charge outranks the stall hiding behind it, at-risk money is the duplicate only, UNKNOWN_STALL admits low confidence, delivered orders never flagged).
  • workflow.test.ts — end to end over the real MCP protocol via an in-memory transport, so tool registration, schema validation, and the response envelope are all exercised. Also asserts the parts of the surface a client sees before any tool call: that execute_remediation is the only tool flagged destructive, that the server instructions state the approval rule, and that the runbook resource and triage prompt resolve. Includes the money invariant (refunded never exceeds captured) and that a second refund is refused.
  • safety.test.ts — the adversarial set: forged token, edited payload, expired token, replayed token, token handed between users, stale precondition, idempotent retry, key reuse across different actions, the three policy verdicts, and rollback when a downstream system refuses.

Runtime verification against the deployed instance is in scripts/remote-smoke.sh.

One test failure was a real bug, not a bad expectation: a $939 refund hit the agent's daily cap and returned blocked when it should have routed to a manager. The agent was never going to execute it — the approver's limits are the ones that matter. Fixed in policy.ts.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选