# Rubin Exchange (remote · mcp.mainnet.rubin.trade)

Rubin: self-custody DEX for crypto perpetuals & spot - trade, read positions, orders, balances.

- Trust score: 66/100 (medium)
- Change this week: +3
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `mcp.mainnet.rubin.trade`: 66/100 (this document), [markdown](https://verifymcp.io/servers/trade-rubin-exchange/mcp.md), [page](https://verifymcp.io/servers/trade-rubin-exchange/mcp)

## Channel facts

- Endpoint: `https://mcp.mainnet.rubin.trade/mcp`
- Transports: `streamable-http`
- Auth: `required`
- Version: `1.0.2`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 57/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation check failed: no authorisation is required to call this server, and it exposes a tool marked destructive (cancel_order).
  - HTTPS is enforced; there's no plaintext access path.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 80/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 3639 tokens (~139/item across 26 items; 26 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 85/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 54% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add --transport http trade-rubin-exchange https://mcp.mainnet.rubin.trade/mcp
```

### Codex

```toml
[mcp_servers.trade-rubin-exchange]
url = "https://mcp.mainnet.rubin.trade/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "trade-rubin-exchange": {
      "type": "remote",
      "url": "https://mcp.mainnet.rubin.trade/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add trade-rubin-exchange --url https://mcp.mainnet.rubin.trade/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  trade-rubin-exchange:
    url: "https://mcp.mainnet.rubin.trade/mcp"
```

### Other

```json
{
  "mcpServers": {
    "trade-rubin-exchange": {
      "type": "http",
      "url": "https://mcp.mainnet.rubin.trade/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-02 (score 66, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 65, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 65, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 64, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 63, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 62)

First indexed and scored.

## MCP tools (26)

### `whoami` (~57 tokens)

Describe this session

Report what this session controls: the master account/subaccount, whether it can trade or is read-only, and the exact on-chain authorization scope (which messages, which subaccount, and that it CANNOT withdraw/transfer). Call this first.

### `get_block_height` (~26 tokens)

Get latest block height

Return the latest chain block height. Useful for SHORT_TERM order goodTilBlock math.

### `list_markets` (~42 tokens)

List perpetual markets

List all perpetual markets with ticker, status and oracle price. Use this first to discover valid market tickers (e.g. BTC-USD) before placing orders.

### `get_market` (~53 tokens)

Get a perpetual market

Get details for one perpetual market (clobPairId, atomicResolution, quantumConversionExponent, tick/step sizes, oracle price, status).

Input parameters:

- `market` (string, required): Market ticker, e.g. BTC-USD

### `get_orderbook` (~57 tokens)

Get orderbook

Get the live orderbook (bids/asks) for a market, optionally truncated to a depth.

Input parameters:

- `depth` (integer): Max levels per side
- `market` (string, required): Market ticker, e.g. BTC-USD

### `get_candles` (~91 tokens)

Get candles (OHLCV)

Get OHLCV candles for a market at a given resolution. Useful for trend/volatility analysis.

Input parameters:

- `fromISO` (string): ISO 8601 start time
- `limit` (integer)
- `market` (string, required): Market ticker, e.g. BTC-USD
- `resolution` (string, required): Candle resolution
- `toISO` (string): ISO 8601 end time

### `get_candles_multi` (~172 tokens)

Get multi-timeframe candles

Get recent OHLCV candles for a market across MULTIPLE resolutions in one call — by default ALL indexer resolutions (1MIN, 5MINS, 15MINS, 30MINS, 1HOUR, 4HOURS, 1DAY) — so the agent can read the trend across timeframes at once. Returns { candles: { <resolution>: [...] } }, newest first. Lower `limit` (e.g. 20) or pass a `resolutions` subset to keep the payload small.

Input parameters:

- `limit` (integer): Candles per resolution (default 50, most recent).
- `market` (string, required): Market ticker, e.g. BTC-USD
- `resolutions` (array): Subset of resolutions (default: all indexer resolutions).

### `get_balance` (~36 tokens)

Get balances

Get the subaccount collateral (USDC asset position) and the on-chain wallet bank balances (gas). Collateral is what backs trading.

### `get_equity` (~30 tokens)

Get account summary

Get the subaccount summary: equity, freeCollateral, marginEnabled, open perpetual positions and asset positions.

### `get_positions` (~95 tokens)

Get perpetual positions

Get perpetual POSITIONS with size, side, entryPrice, unrealizedPnl, realizedPnl and netFunding. Defaults to OPEN positions. NOTE: a position is what you HOLD after an order fills — it is NOT an open order. When the user asks loosely "what is open?", check BOTH this and get_open_orders (or call get_portfolio for both at once).

Input parameters:

- `status` (string): Position status filter

### `get_open_orders` (~135 tokens)

Get open orders

Get currently active ORDERS for the subaccount, optionally filtered by market and side. Includes OPEN resting orders and UNTRIGGERED conditional orders (TP/SL accepted on-chain but not yet triggered). Returns { orders: [...] }. This does NOT include filled positions — a filled market/limit order leaves NO open order, it becomes a POSITION (see get_positions). When there are 0 orders but open positions exist, the result carries a `note` pointing you there.

Input parameters:

- `limit` (integer)
- `market` (string): Market ticker filter, e.g. BTC-USD
- `side` (string)

### `get_portfolio` (~94 tokens)

Get full portfolio

One-call snapshot of everything the account has "open": equity & freeCollateral, every open POSITION (with notional, unrealized PnL and estimated liquidation price), every active ORDER (resting + untriggered TP/SL), and account margin risk. Use this to answer "what do I have open?" or "how am I doing?" without worrying whether the user means orders or positions — it returns both.

### `get_position_risk` (~85 tokens)

Get position risk

Margin health for the subaccount: equity, freeCollateral, total maintenance/initial margin, maintenanceMarginBufferUsd (the EXACT liquidation guard — liquidatable when < 0), marginUsageRatio (1.0 = at liquidation), account leverage, and per-position estimated liquidation price + distance to it. Use before adding risk or to decide whether to protect/close a position.

### `get_fills` (~60 tokens)

Get fills (trade history)

Get executed fills for the subaccount, including price, size, fee and maker/taker liquidity.

Input parameters:

- `limit` (integer)
- `market` (string): Market ticker filter, e.g. BTC-USD
- `page` (integer)

### `get_pnl` (~72 tokens)

Get historical PnL

Get historical PnL ticks for the subaccount (equity, totalPnl, netTransfers over time). Use createdOnOrAfter to bound the range.

Input parameters:

- `createdOnOrAfter` (string): ISO 8601 lower bound
- `limit` (integer)
- `page` (integer)

### `place_limit_order` (~296 tokens)

Place a limit order

Place a limit order. Default timeInForce=GTT (long-term, durable, broadcast-commit so errors return synchronously). Use SHORT_TERM only for latency-sensitive orders (expire within ~20 blocks, broadcast async). NOTE: stateful (GTT) orders are rate-limited to 2/block and 20 per 100 blocks — pace placements. Returns `confirmation` with the REAL outcome verified via the indexer (filled / partially_filled / resting / unfilled / pending) — broadcast `code: 0` only means the tx was accepted, NOT that it filled. Report from `confirmation.outcome`; if it is `pending`, the indexer is lagging — re-check shortly.

Input parameters:

- `clientId` (integer)
- `confirm` (boolean): Verify the real outcome via the indexer after broadcast (default true).
- `goodTilBlockOffset` (integer): SHORT_TERM blocks ahead (default 10)
- `goodTilTimeSeconds` (integer): GTT lifetime (default 3600)
- `market` (string, required): Market ticker, e.g. BTC-USD
- `postOnly` (boolean): Reject if it would cross (maker-only). Defaults to server config.
- `price` (number, required)
- `reduceOnly` (boolean)
- `side` (string, required)
- `size` (number, required): Size in base units
- `timeInForce` (string)

### `place_market_order` (~310 tokens)

Place a market order

Place an IOC market order. It executes as an IOC limit at a worst-acceptable price mirrored around the oracle by side — BUY caps ABOVE the oracle, SELL below — at slippageBps distance (default 500 = 5%). Fills happen at book prices; the cap only limits how deep the sweep goes. reduceOnly closes an existing position. Returns `confirmation` with the REAL outcome verified via the indexer (filled / partially_filled / unfilled / pending): broadcast `code: 0` only means the tx was accepted — an IOC order cancels UNFILLED when the book is entirely beyond the slippage cap (thin/spread market). Always report from `confirmation.outcome`, not `code`; if `unfilled` or `partially_filled`, retry with a larger slippageBps to sweep deeper; if `pending`, the indexer is lagging — wait a few seconds and re-check before concluding.

Input parameters:

- `clientId` (integer)
- `confirm` (boolean): Verify the real fill via the indexer after broadcast (default true).
- `market` (string, required): Market ticker, e.g. BTC-USD
- `reduceOnly` (boolean)
- `side` (string, required)
- `size` (number, required): Size in base units
- `slippageBps` (number): Max slippage vs oracle, in bps (default 500). BUY bounds above the oracle, SELL below; raise to sweep a thin book.

### `cancel_order` (~161 tokens)

Cancel an order

Cancel a single order by clientId. For SHORT_TERM pass goodTilBlock; for LONG_TERM/CONDITIONAL pass goodTilTimeSeconds (the original good-til value, available from get_open_orders). Returns `confirmation` with the verified result (canceled / still_open / filled / pending): `code: 0` only means the cancel was broadcast. If `still_open`, the goodTil value likely did not match the original — retry.

Input parameters:

- `clientId` (integer, required)
- `confirm` (boolean): Verify the cancel actually took via the indexer (default true).
- `goodTilBlock` (integer)
- `goodTilTimeSeconds` (integer)
- `market` (string, required)
- `orderFlags` (string, required)

### `cancel_all_orders` (~85 tokens)

Cancel all orders in a market

Cancel every OPEN order for the subaccount in a market (handles SHORT_TERM and LONG_TERM automatically). Returns `confirmation.remainingOpen` — orders still OPEN after the cancel (0 = all gone); if > 0, retry.

Input parameters:

- `confirm` (boolean): After canceling, verify no orders remain OPEN via the indexer (default true).
- `market` (string, required)

### `batch_cancel` (~50 tokens)

Batch cancel short-term orders

Cancel multiple SHORT_TERM orders in one tx. SHORT_TERM only (chain limitation) — for stateful/mixed use cancel_all_orders.

Input parameters:

- `clientIds` (array, required)
- `market` (string, required)

### `place_stop_loss` (~158 tokens)

Stop loss

Place a reduce-only Stop loss (conditional market order) that triggers at triggerPrice. Side must be the CLOSING side of the position: SELL closes a LONG, BUY closes a SHORT. Once triggered it executes as an IOC limit bounded at triggerPrice ± slippageBps in the direction of execution (BUY above the trigger, SELL below; default 500 bps) so the close can cross the book.

Input parameters:

- `clientId` (integer)
- `market` (string, required)
- `side` (string, required)
- `size` (number, required)
- `slippageBps` (number): Execution bound past the trigger, in bps (default 500). Raise for thin books.
- `triggerPrice` (number, required)

### `place_take_profit` (~158 tokens)

Take profit

Place a reduce-only Take profit (conditional market order) that triggers at triggerPrice. Side must be the CLOSING side of the position: SELL closes a LONG, BUY closes a SHORT. Once triggered it executes as an IOC limit bounded at triggerPrice ± slippageBps in the direction of execution (BUY above the trigger, SELL below; default 500 bps) so the close can cross the book.

Input parameters:

- `clientId` (integer)
- `market` (string, required)
- `side` (string, required)
- `size` (number, required)
- `slippageBps` (number): Execution bound past the trigger, in bps (default 500). Raise for thin books.
- `triggerPrice` (number, required)

### `close_position` (~246 tokens)

Close a position

Close all or part of an open perpetual position with a reduce-only MARKET order. Reads the current position, flips the side automatically (LONG→SELL, SHORT→BUY) and sizes the close. percent defaults to 100 (full close); a partial close is floored to the market step size. The close is bounded at oracle ± slippageBps mirrored by side (closing a SHORT buys up to oracle×(1+slip), closing a LONG sells down to oracle×(1−slip); default 500 bps = 5%). Returns the verified `confirmation` outcome — if it is `unfilled` or `partially_filled`, the book was thinner than the cap: re-run with a larger slippageBps to sweep deeper. Errors NOT_FOUND if there is no open position in the market.

Input parameters:

- `confirm` (boolean)
- `market` (string, required): Market ticker, e.g. BTC-USD
- `percent` (number): Portion of the position to close (default 100).
- `slippageBps` (number): Max slippage vs oracle, in bps (default 500). Raise to sweep a thin book.

### `close_all_positions` (~129 tokens)

Close all positions

Flatten EVERY open perpetual position with reduce-only MARKET orders (one per market). Respects the operator market allowlist (disallowed markets are skipped and reported). Each close is bounded at oracle ± slippageBps mirrored by side (default 500 bps = 5%). Returns a per-market result array — for any market reporting unfilled/partially_filled, re-run with a larger slippageBps.

Input parameters:

- `confirm` (boolean)
- `slippageBps` (number): Max slippage vs oracle, in bps (default 500). Raise to sweep thin books.

### `open_position` (~278 tokens)

Open a position (market entry + optional bracket)

Enter a NEW position with a MARKET order, sized by base `size` OR quote `notionalUsd` (exactly one required; notionalUsd converts at the oracle price and is floored to the step size). Optionally attach a reduce-only stopLossPrice and/or takeProfitPrice as conditional orders in the SAME call (the bracket, placed with the opposite/closing side and a 500 bps execution bound past the trigger). slippageBps caps the entry fill vs oracle (default 500). Returns the entry `confirmation` plus any bracket order ids. Bracket legs are placed only if the entry broadcast succeeds; each is reduce-only so it can only close, never flip.

Input parameters:

- `confirm` (boolean)
- `market` (string, required): Market ticker, e.g. BTC-USD
- `notionalUsd` (number): Position size in quote USD (converted at oracle). Use instead of size.
- `side` (string, required)
- `size` (number): Position size in base units.
- `slippageBps` (number): Max slippage vs oracle for the entry, in bps (default 500).
- `stopLossPrice` (number): Attach a reduce-only stop-loss trigger at this price.
- `takeProfitPrice` (number): Attach a reduce-only take-profit trigger at this price.

### `get_news` (~240 tokens)

Get latest news

Fetch the latest headlines from the ritbit news feed (curated crypto / markets / business channels, newest first). Filter by `category` (crypto|markets|business) or explicit `channels`, and/or a free-text `query` (a ticker or keyword, matched in the post text and hashtags, e.g. BTC). Each item returns { source, url, publishedAt, tags (hashtags — where tickers appear), text }. There is NO importance field: judge impact yourself from the content (hacks, regulation, large moves, ⚠️ warnings). Use this to factor sentiment/catalysts into an assessment, or to answer "what's the latest?". Headlines are ru/en.

Input parameters:

- `category` (string): Restrict to one channel category.
- `channels` (array): Explicit hub channel ids (overrides category), e.g. ["forklog","incrypted"].
- `limit` (integer): Max items (default 30).
- `query` (string): Case-insensitive keyword/ticker to match in text or hashtags, e.g. BTC.
- `sinceHours` (number): Only items newer than this many hours.

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/trade-rubin-exchange/mcp#diagnostics

## Score history

- 2026-08-03: 66
- 2026-08-02: 66
- 2026-08-01: 65
- 2026-07-31: 65
- 2026-07-30: 65
- 2026-07-29: 64
- 2026-07-28: 63
- 2026-07-27: 63
- 2026-07-26: 62

## Links

- Remote endpoint: https://mcp.mainnet.rubin.trade/mcp
- Authorisation metadata: https://mcp.mainnet.rubin.trade/.well-known/oauth-protected-resource/mcp
- Repository: https://github.com/rubin-trade/rubin-mainnet-mcp
- Website: https://code.rubin.trade/ai
- Changelog RSS feed: https://verifymcp.io/servers/trade-rubin-exchange/mcp/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/trade-rubin-exchange/mcp/changelog.json
- HTML version of this page: https://verifymcp.io/servers/trade-rubin-exchange/mcp
