MONARKFleetNarabiUkemiBellit abstains so DeFi can act.
Documentation menu
docs · integratorsbuilt

The engine, reachable by your agent.

The harness makes the gate callable over MCP and over a plain HTTP mirror. The endpoint is public and unauthenticated, with no availability commitment. What you send and what you get back are frozen contracts with closed keys, and they will not change without a versioned revision. Snapshot of the served harness as read at 2026-09-25T03:26:05.861Z, version 0.4.0.

Reach the engine

An agent reaches the engine over MCP or the HTTP mirror, calls a served tool and gets a frozen decision back.Your agentany MCP client, or anyprogram that can POSTno account, e-mail or walletMCP, streamable HTTPhttps://mcp.monarkgate.tech/mcpplain HTTP mirrorhttps://api.monarkgate.techTHE SERVED TOOLSattestreal, notary Shōgen, demonstrative,not probativecalibratesplit-conformal quantile atmiscoverage α over caller-suppliednonconformity scorescascadeThis cascade tool is v0gateThe gate only emits a decision; itnever calls the named tool.GateDecisioncommit, deferor abstain,and why
How an agent reaches the engine. The endpoints, the tools and their notes are read from the served harness; the answer is the frozen GateDecision.

The server is listed in the MCP registry as tech.monarkgate/monark, version 0.4.0, status active. The HTTP mirror is described by /openapi.json (OpenAPI 3.1.0). In the served words: The gate only emits a decision; it never calls the named tool.

Add it in one line

hermes mcp add monark --url https://mcp.monarkgate.tech/mcp
openclaw mcp add monark --url https://mcp.monarkgate.tech/mcp --transport streamable-http

Any other MCP client: point it at https://mcp.monarkgate.tech/mcp (streamable-http). The Accept header, as recorded against an in-process server on 127.0.0.1: application/json, text/event-stream (a request missing text/event-stream is answered 406).

A gate call, as recorded

One request and its answer, recorded over the MCP transport of an in-process server on 127.0.0.1. The class it names, btc-dir-15m, is served as declared synthetic — a plumbing fixture, not a measured predictor.

you send (the arguments of the tool call)
{
  "prediction": {
    "schema_version": "1.0.0",
    "task_class": "btc-dir-15m",
    "yhat": "up",
    "predictor_id": "internal:momentum-4c",
    "produced_at": "2026-09-04T00:00:00Z"
  },
  "params": {
    "bFloor": 0,
    "tau": 1,
    "tauInterval": 1,
    "alpha": 0.1,
    "nMin": 50,
    "tool": "perps_order_preview",
    "clockOpen": true,
    "remainingBudget": 0.1,
    "intent": "up"
  }
}
you get back (structuredContent)
{
  "schema_version": "1.0.0",
  "action": "commit",
  "allow": true,
  "tool": "perps_order_preview",
  "intent": "up",
  "verdict": {
    "schema_version": "1.0.0",
    "task_class": "btc-dir-15m",
    "method": "split",
    "alpha": 0.1,
    "n_calib": 150,
    "region": {
      "kind": "set",
      "labels": [
        "up"
      ],
      "label_schema": "up|down"
    },
    "qhat": 0,
    "abstain": false,
    "reason": "covered",
    "residual": [],
    "calib_digest": "fcebed27fd3f9607bba94898f5ae4ebba548ced519d1d800b49890235358eda6",
    "produced_at": "2026-09-04T00:00:00Z"
  },
  "remaining_budget": 0.1,
  "reason": "covered"
}

Bring your own calibration

Two stateless calls. You calibrate on your own nonconformity scores, then gate your own prediction under them. The audit closes when the decision’s calib_digest equals the calibration’s set_digest.

The bring-your-own loop: calibrate on your own scores, then gate your prediction under them; the digests tie the two calls.First: calibrateyou send your nonconformity scores,a miscoverage level and a minimum countset_digest 4081f7184e42…Then: gateyour prediction, your terms, and the samescores as the calibration parametercalib_digest 4081f7184e42…The answercommit · coveredThe audit closes: the two digests are equal.The decision was gated against exactly the scores you calibrated. MONARK does not see your data or your model, and doesnot check that your numbers are nonconformity scores of any model: the coverage is yours to own.
The bring-your-own loop, with the digests and the answer read from the loop recorded over the transport.
first call, calibrate: you send
{
  "scores": [
    0.1,
    0.2,
    0.3,
    0.4,
    0.5,
    0.6,
    0.7,
    0.8,
    0.9,
    1
  ],
  "alpha": 0.1,
  "nMin": 5
}
first call, calibrate: you get back (its label field is quoted below)
{
  "qhat": 1,
  "n": 10,
  "alpha": 0.1,
  "method": "split",
  "set_digest": "4081f7184e42b34e594015191f04720343b8b37691c7e4412c2469efdc43dd3a",
  "reason": null
}
second call, gate: you send
{
  "prediction": {
    "schema_version": "1.0.0",
    "task_class": "caller-demo-reg",
    "yhat": 0,
    "predictor_id": "caller:own-model",
    "produced_at": "2026-09-04T00:00:00Z"
  },
  "params": {
    "remainingBudget": 0.1,
    "bFloor": 0,
    "tau": 1,
    "tauInterval": 3,
    "alpha": 0.1,
    "nMin": 5,
    "intent": 0,
    "tool": "caller_downstream_tool",
    "clockOpen": true,
    "calibration": {
      "scores": [
        0.1,
        0.2,
        0.3,
        0.4,
        0.5,
        0.6,
        0.7,
        0.8,
        0.9,
        1
      ],
      "mode": "interval"
    }
  }
}
second call, gate: you get back
{
  "schema_version": "1.0.0",
  "action": "commit",
  "allow": true,
  "tool": "caller_downstream_tool",
  "intent": 0,
  "verdict": {
    "schema_version": "1.0.0",
    "task_class": "caller-demo-reg",
    "method": "split",
    "alpha": 0.1,
    "n_calib": 10,
    "region": {
      "kind": "interval",
      "lo": -1,
      "hi": 1
    },
    "qhat": 1,
    "abstain": false,
    "reason": "covered",
    "residual": [],
    "calib_digest": "4081f7184e42b34e594015191f04720343b8b37691c7e4412c2469efdc43dd3a",
    "produced_at": "2026-09-04T00:00:00Z"
  },
  "remaining_budget": 0.1,
  "reason": "covered"
}

What you send, what you get back

POST /gate
prediction + params, optional attested, closed keys
Prediction
schema_version · task_class · yhat · predictor_id · produced_at
GateDecision
schema_version · action · allow · tool · intent · verdict · remaining_budget · reason
CoverageVerdict
schema_version · task_class · method · alpha · n_calib · region · qhat · abstain · reason · residual · calib_digest · produced_at
reasons
one of 13 codes of a closed list (see the gate page)
budget
B_t is caller-carried: the value you send comes back unchanged
  • params.remainingBudget, number, required: B_t — remaining authorization capacity (caller-owned).
  • params.bFloor, number, required: B_floor threshold (>= 0).
  • params.tau, number, required: Set-size threshold for the `set` path (>= 0).
  • params.tauInterval, number, required: Width threshold for the `interval` path (>= 0).
  • params.alpha, number, required: Target miscoverage in (0,1).
  • params.nMin, integer, required: Minimum calibration count (>= 1).
  • params.intent, string | number | null, required: The intent tested against the region.
  • params.tool, string, required: The NAMED gated tool (echoed, never invoked).
  • params.clockOpen, boolean, required: Whether the coverage window is still open (caller-owned).
  • params.calibration, object, optional: OPTIONAL BYO calibration: caller-supplied nonconformity scores + region mode. Present ⇒ the gate conformalizes on the caller's model, not a committed class.

The classes it serves

task classcalibrationserved clauses
btc-dir-15msynthetic fixturedeclared synthetic — a plumbing fixture, not a measured predictor.
cascade-liquidable-24hno calibration committedno cascade calibration is committed; the gate abstains (under_calib) on this class.
stable-run-velocity-24hcommitteda committed stable-run velocity calibration for the USDe synthetic-dollar-whitelisted-redeem population; over calm-window redemption flow; the calibration is measured non-stationary across half-years; no coverage is measured; for any other population, no stable-run velocity calibration is committed for this population; the gate abstains (under_calib).
liquidation-eligible-coveragecommitteda conformal upper bound on the liquidable amount for the calibrated class; the lower edge is 0 by construction, not a calibrated bound; abstains (under_calib) outside it; this class requires alpha = 0.01, nMin = 100; calibrated on one recorded episode; no coverage is claimed on any other event; the H-3 exchangeability check is a report, a YES licenses nothing more; the bound holds only if yhat was produced by the frozen close-factor rule on a mono-collateral WETH account at the first crossing, which the gate does not check.
your own classyour calibrationthe gate conformalizes against THOSE caller-supplied scores (BYO).

Refusals and bounds

  • A payload carrying an unknown key is refused, not ignored: 400, Input failed the frozen schema, or the tool refused the input (never a silent result).
  • A payload carrying a forbidden key throws instead of serialising: there is no score field to send.
  • A foreign browser origin is refused: 403, Origin present and not a monarkgate.tech origin.
  • Served bounds: at most 10000 scores per calibration, 10000 per gate calibration, 10000 candidates in set mode, 64 nodes per cascade.
  • Last deploy check 2026-09-25T03:24:23.912Z: 13 of 13 controls passed.

The integrators page carries the same facts in full.