StableOps
Agents

MCP Server

Expose scoped tools to AI agents over MCP.

@stableops/mcp-server is a stdio MCP server that wraps the StableOps SDK as a fixed set of tools. AI agents (Claude Desktop, Cursor, any MCP-compatible host) can call these tools only — they cannot talk to the API directly, and every call is gated by the workspace's agent policy.

What the toolkit exposes

ToolKindDescription
get_orderreadLook up one payment order by id.
list_eventsreadQuery the normalized chain-event log.
list_webhook_deliveriesreadRead recent webhook deliveries.
create_payment_orderwriteOpen a new payment order (policy-gated).
request_action_approvalwriteQueue a sensitive action for a human to approve.

Read tools default to auto_allowed. Write tools always go through POST /v1/agent/actions first; if the policy says require_approval=true, the call returns pending_approval and the agent must wait for a human to approve in the dashboard.

Run the server

pnpm add -g @stableops/mcp-server   # or use npx for one-shot usage

STABLEOPS_API_URL=https://api.stableops.dev \
STABLEOPS_API_KEY=sk_sandbox_xxx \
STABLEOPS_ORG_SLUG=demo \
STABLEOPS_ENVIRONMENT=sandbox \
STABLEOPS_AGENT_SESSION_ID=agent_sess_01 \
  stableops-mcp

Every variable is read from the process environment:

VariableRequiredDefaultNotes
STABLEOPS_API_URLnohttp://localhost:3001Override for self-hosted or sandbox.
STABLEOPS_API_KEYyesSent as Authorization: Bearer ….
STABLEOPS_ORG_SLUGnodemoSent as x-stableops-org.
STABLEOPS_ENVIRONMENTnosandboxsandbox or live.
STABLEOPS_AGENT_SESSION_IDyesBind this MCP process to one audited session.

Create the session id first with POST /v1/agent/sessions so the dashboard can show its actions and revoke it later.

Wire it into Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "stableops": {
      "command": "stableops-mcp",
      "env": {
        "STABLEOPS_API_URL": "https://api.stableops.dev",
        "STABLEOPS_API_KEY": "sk_sandbox_xxx",
        "STABLEOPS_ORG_SLUG": "demo",
        "STABLEOPS_ENVIRONMENT": "sandbox",
        "STABLEOPS_AGENT_SESSION_ID": "agent_sess_01"
      }
    }
  }
}

Cursor and other MCP hosts take the same shape — a command, args, and env.

Embed in your own host

If you build a custom Node host you can create the server directly without shelling out to the binary:

import { createAgentToolkitServer } from '@stableops/mcp-server'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'

const server = createAgentToolkitServer({
  apiKey: process.env.STABLEOPS_API_KEY!,
  baseUrl: process.env.STABLEOPS_API_URL,
  organizationSlug: 'demo',
  environment: 'sandbox',
  agentSessionId: 'agent_sess_01',
})

await server.connect(new StdioServerTransport())

Lifecycle of a tool call

agent ─▶ tool call ─▶ POST /v1/agent/actions

                       ├── decision = auto_allowed   ─▶ SDK call ─▶ POST /actions/:id/executed
                       └── decision = pending_approval ─▶ blocked response

                                                          (human approves in dashboard,
                                                           agent re-attempts the tool call)

Every tool returns either a structured result (typed against the tool's outputSchema) or an isError envelope. The structured shape mirrors what the SDK returns from the underlying resource call — camelCase keys, the same enum values you see on /v1/payment-orders.

Safety properties

  • The agent cannot sign chain transactions. The toolkit only opens StableOps payment orders; outbound treasury movements need a human in the dashboard.
  • The agent cannot bypass the policy. Even read tools go through /v1/agent/actions, so revoking the session blocks every subsequent call mid-conversation.
  • Prompt injection that asks the agent to call create_payment_order outside the allow-list falls through to pending_approval — the worst case is a queued action a human sees, not a live payment.

Next

On this page