Skip to main content
Glama
dwin-gharibi

ramzinex-mcp

by dwin-gharibi
README.md
<div align="center">

<img src="assets/banner.svg" alt="ramzinex-mcp" width="100%" />

<h1>
  ramzinex-mcp
</h1>

**A self-hostable [Model Context Protocol](https://modelcontextprotocol.io) server for the [Ramzinex](https://ramzinex.com) (رمزینکس) cryptocurrency exchange.**

[![CI](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/ci.yml)
[![Docker](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/docker.yml/badge.svg)](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/docker.yml)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

</div>

---

> **Unofficial integration.** This is a community-built MCP server. The
> "Ramzinex" name and logo belong to their owner. Not affiliated with, endorsed
> by, or sponsored by Ramzinex. Trading carries risk — use the order tools at
> your own risk.

## What is this?

`ramzinex-mcp` exposes the Ramzinex exchange API as MCP **tools** and **prompts**
so an LLM agent (Claude, etc.) can read markets, inspect an account, and — when
you explicitly allow it — place and cancel orders. It is a small, stateless,
async Python process you run yourself.

<div align="center">
<img src="assets/illustrations/gold-bars-phone.png" alt="" height="150" />
&nbsp;&nbsp;&nbsp;
</div>

It mirrors the structure and quality of the sibling `roshan-*-mcp` servers:
typed `httpx` client, `pydantic-settings` configuration, full test suite, Docker
/ Helm / Kubernetes / Terraform deploy assets, and generated architecture
diagrams.

<div align="center">
<img src="assets/illustrations/spot-2.svg" alt="" height="120" />
</div>

## Public vs. private — and the trading guardrail

Ramzinex has **two API bases**, and this server routes each call to the right
one automatically:

<div align="center">
<img src="assets/illustrations/spot-1.svg" alt="" height="120" />
</div>

| Surface | Base URL | Auth | Tools |
| --- | --- | --- | --- |
| **Public** | `https://publicapi.ramzinex.com` | none | market data (pairs, orderbooks, prices, currencies, networks) |
| **Private** | `https://ramzinex.com` | `Authorization2: Bearer <token>` + `x-api-key: <api_key>` | orders, funds/balances, deposits, withdrawals, addresses, rewards/commissions, API-key access management |

> ### 🔐 Auth headers (Postman-accurate)
> The live Ramzinex private API requires **two non-standard headers** — **not**
> the usual `Authorization`:
> ```
> Authorization2: Bearer <token>
> x-api-key: <api_key>
> ```
> The header name carrying the token is configurable via `auth_header_name`
> (default `Authorization2`; set it to `Authorization` for legacy compatibility),
> and `x-api-key` is sent whenever an `api_key` is configured (`send_x_api_key`
> now defaults **`true`**). See [Authentication](#authentication-api_token-vs-api_key--secret).

> ### ⚠️ Money-moving & account-control safety
> Some actions move real money or change what your API keys can do. They are
> gated by **three separate** per-instance flags, all default **`false`**:
> - **`enable_trading`** gates `ramzinex_place_limit_order`,
>   `ramzinex_place_market_order`, `ramzinex_cancel_order`.
> - **`enable_withdrawals`** gates `ramzinex_submit_withdraw`,
>   `ramzinex_confirm_withdraw`, and `ramzinex_allocate_address` (creating a
>   deposit address is a wallet-write).
> - **`account_control`** gates `ramzinex_edit_general_access` and
>   `ramzinex_edit_private_access` (API-key access management).
>
> A master **`read_only`** flag forces **all three** off regardless of their
> values. When a gate is off the tool returns a structured refusal and **never
> calls the API**:
> ```json
> {"error": "trading_disabled", "message": "Set enable_trading=true (and read_only=false) on this instance to allow order placement/cancellation."}
> ```
> Read-only tools (market data, viewing balances/orders) are always allowed.
> Tokens / secrets / api keys are never logged and are redacted from every error
> message. See [Control flags & safety](#control-flags--safety) below.


> Order lifecycle — placing is gated by `enable_trading`:

![order-lifecycle](assets/diagrams/order-lifecycle.png)

> Withdrawals are separately gated by `enable_withdrawals` and require 2FA confirmation:

![withdrawal-flow](assets/diagrams/withdrawal-flow.png)

## Install

```bash
pip install -e .            # from a checkout
# or, for development:
pip install -e ".[dev]"
```

Requires Python 3.10+.

## Quick start

Public market data needs no configuration at all:

```bash
python -m ramzinex_mcp          # stdio transport (default)
```

To use private (account) tools, authenticate with **either** a pre-issued bearer
token **or** an api_key + secret pair (the server exchanges it for a token via
the `getToken` login flow and re-issues automatically on a 401):

```bash
# Option A: pre-issued bearer token
export RAMZINEX_API_TOKEN=your-personal-api-token

# Option B: api_key + secret login flow (api_token wins if both are set)
export RAMZINEX_API_KEY=your-api-key
export RAMZINEX_SECRET=your-api-secret
# x-api-key is sent by default; the token rides in the Authorization2 header.
# export RAMZINEX_SEND_X_API_KEY=false      # opt out of the x-api-key header
# export RAMZINEX_AUTH_HEADER_NAME=Authorization  # legacy header-name mode

# Opt in to the gated tools (all default false):
export RAMZINEX_ENABLE_TRADING=true        # allow placing/cancelling orders
export RAMZINEX_ENABLE_WITHDRAWALS=true    # allow withdrawals + address allocation
export RAMZINEX_ACCOUNT_CONTROL=true       # allow API-key access management
python -m ramzinex_mcp
```

Run over HTTP for networked clients:

```bash
python -m ramzinex_mcp --transport streamable-http --host 0.0.0.0 --port 8000
```

## Configuration (multi-account / multi-instance)

Configuration is read from environment variables via `pydantic-settings`. One
process can front **many Ramzinex accounts** — each is a named *instance* with
its own token and trading policy. Every API tool accepts an optional `instance`
argument; omit it to use the default.

<div align="center">
<img src="assets/illustrations/spot-4.svg" alt="" height="120" />
</div>

### Shorthand (single default instance)

| Variable | Default | Description |
| --- | --- | --- |
| `RAMZINEX_API_TOKEN` | — | Pre-issued bearer token for private endpoints (wins over api_key+secret). |
| `RAMZINEX_API_KEY` | — | API key for the `getToken` login flow (with `RAMZINEX_SECRET`); also sent as `x-api-key`. |
| `RAMZINEX_SECRET` | — | API secret paired with `RAMZINEX_API_KEY`. |
| `RAMZINEX_AUTH_HEADER_NAME` | `Authorization2` | Header that carries the bearer token (set `Authorization` for legacy mode). |
| `RAMZINEX_SEND_X_API_KEY` | `true` | Also send `x-api-key: <api_key>` on private calls (the live API needs it). |
| `RAMZINEX_PUBLIC_BASE_URL` | `https://publicapi.ramzinex.com` | Public base URL. |
| `RAMZINEX_PRIVATE_BASE_URL` | `https://ramzinex.com` | Private base URL. |
| `RAMZINEX_API_VERSION` | `v1.0` | API version segment for the exchange paths. |
| `RAMZINEX_ENABLE_TRADING` | `false` | Allow placing/cancelling orders. |
| `RAMZINEX_ENABLE_WITHDRAWALS` | `false` | Allow withdrawals + deposit-address allocation. |
| `RAMZINEX_ACCOUNT_CONTROL` | `false` | Allow API-key access management (edit general/private access). |
| `RAMZINEX_READ_ONLY` | `false` | Master switch: forces all three gates off. |
| `RAMZINEX_VERIFY_SSL` | `true` | Verify TLS certificates. |
| `RAMZINEX_TIMEOUT` | `30` | Per-request timeout (seconds). |
| `RAMZINEX_DEFAULT_INSTANCE` | `default` | Instance used when `instance` is omitted. |
| `RAMZINEX_LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARNING` / ... |

### Nested (named instances)

| Variable | Description |
| --- | --- |
| `RAMZINEX__INSTANCES__<NAME>__API_TOKEN` | Pre-issued bearer token for instance `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__API_KEY` | API key for `<NAME>`'s getToken login flow (also sent as `x-api-key`). |
| `RAMZINEX__INSTANCES__<NAME>__SECRET` | API secret for `<NAME>`'s getToken login flow. |
| `RAMZINEX__INSTANCES__<NAME>__AUTH_HEADER_NAME` | Bearer-token header name for `<NAME>` (default `Authorization2`). |
| `RAMZINEX__INSTANCES__<NAME>__SEND_X_API_KEY` | Send `x-api-key` on `<NAME>`'s private calls (default `true`). |
| `RAMZINEX__INSTANCES__<NAME>__ENABLE_TRADING` | Trading switch for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__ENABLE_WITHDRAWALS` | Withdrawals + address-allocation switch for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__ACCOUNT_CONTROL` | API-key access-management switch for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__READ_ONLY` | Master switch (forces all three gates off) for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__API_VERSION` | API version for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__PUBLIC_BASE_URL` | Public base for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__PRIVATE_BASE_URL` | Private base for `<NAME>`. |
| `RAMZINEX__INSTANCES__<NAME>__VERIFY_SSL` | TLS verification (default `true`). |
| `RAMZINEX__INSTANCES__<NAME>__TIMEOUT` | Per-request timeout seconds (default `30`). |
| `RAMZINEX__DEFAULT_INSTANCE` | Instance used when `instance` is omitted. |
| `RAMZINEX__LOG_LEVEL` | `DEBUG` / `INFO` / `WARNING` / ... |

Example: a read-only personal account, a trading bot using api_key+secret, and a
strictly read-only viewer.

```bash
RAMZINEX__INSTANCES__PERSONAL__API_TOKEN=personal-token
RAMZINEX__INSTANCES__PERSONAL__ENABLE_TRADING=false
RAMZINEX__INSTANCES__BOT__API_KEY=bot-key
RAMZINEX__INSTANCES__BOT__SECRET=bot-secret
RAMZINEX__INSTANCES__BOT__ENABLE_TRADING=true
RAMZINEX__INSTANCES__READONLY__API_TOKEN=viewer-token
RAMZINEX__INSTANCES__READONLY__READ_ONLY=true
RAMZINEX__DEFAULT_INSTANCE=personal
```

See [`.env.example`](.env.example) for a complete, annotated file. Use
`list_instances` to see what's configured (names, base URLs, `api_version`,
`auth_header_name`, `has_credentials`, `auth_method`, `enable_trading`,
`enable_withdrawals`, `account_control`, `read_only`) — it never reveals
credential values.


> Authentication: a pre-issued `api_token`, or `api_key`+`secret` exchanged for a cached Bearer (refreshed on 401):

![auth-flow](assets/diagrams/auth-flow.png)

## Control flags & safety

**Three independent** gates plus a master switch protect the account. Use the
effective `trading_allowed` / `withdrawals_allowed` / `account_control_allowed`
values from `list_instances` (they already fold in `read_only`):

| Flag | Default | Gates | Effective when |
| --- | --- | --- | --- |
| `enable_trading` | `false` | `ramzinex_place_limit_order`, `ramzinex_place_market_order`, `ramzinex_cancel_order` | `enable_trading=true` **and** `read_only=false` |
| `enable_withdrawals` | `false` | `ramzinex_submit_withdraw`, `ramzinex_confirm_withdraw`, `ramzinex_allocate_address` | `enable_withdrawals=true` **and** `read_only=false` |
| `account_control` | `false` | `ramzinex_edit_general_access`, `ramzinex_edit_private_access` | `account_control=true` **and** `read_only=false` |
| `read_only` | `false` | forces **all three** of the above off | — |

When a gate is off, the tool returns
`{"error": "trading_disabled" / "withdrawals_disabled" / "account_control_disabled", "message": ...}`
and **never contacts the API**. `ramzinex_refresh_deposits` is a non-money-moving
refresh and is not gated.

### Authentication: `api_token` vs `api_key` + `secret`

Private endpoints require **two non-standard headers**:
`Authorization2: Bearer <token>` **and** `x-api-key: <api_key>` (the live API
does **not** use the standard `Authorization`). The token-carrying header name is
configurable via `auth_header_name` (default `Authorization2`; set
`Authorization` for legacy mode), and `x-api-key` is sent whenever an `api_key`
is configured (`send_x_api_key` defaults `true`).

- **`api_token`** — a pre-issued bearer token, sent directly as
  `Authorization2: Bearer <token>`. Simplest; takes precedence if both are set.
- **`api_key` + `secret`** — the server POSTs them to
  `auth/api_key/getToken`, caches the returned token in memory per instance,
  reuses it, and re-authenticates once on a `401`. Call `ramzinex_authenticate`
  to trigger/verify the login explicitly (it never returns the token). The
  `api_key` doubles as the `x-api-key` header value. Tokens, secrets, and api
  keys are never logged or echoed (`Authorization2` / `Authorization` /
  `x-api-key` / `secret` / `api_key` are all redacted from errors).


> The `read_only` master switch overrides the trading / withdrawal / account-control gates:

![safety-gates](assets/diagrams/safety-gates.png)

## Use with an MCP client

Add it to your client's MCP server config (stdio):

```json
{
  "mcpServers": {
    "ramzinex": {
      "command": "python",
      "args": ["-m", "ramzinex_mcp"],
      "env": {
        "RAMZINEX_API_TOKEN": "your-personal-api-token",
        "RAMZINEX_ENABLE_TRADING": "false"
      }
    }
  }
}
```

## Tools

All 45 tools (42 service endpoints + 3 meta) accept an optional `instance`
(except the two local meta tools, `list_instances` and `ramzinex_docs`). Private
tools send `Authorization2: Bearer <token>` + `x-api-key: <api_key>`.

### Market data — public, no auth

| Tool | Endpoint |
| --- | --- |
| `ramzinex_get_pairs` | `GET /exchange/api/v1.0/exchange/pairs` |
| `ramzinex_get_pair(pair_id)` | `GET .../pairs/{pair_id}` |
| `ramzinex_get_orderbook(pair_id)` | `GET .../orderbooks/{pair_id}/buys_sells` |
| `ramzinex_get_all_orderbooks` | `GET .../orderbooks/buys_sells` |
| `ramzinex_get_orderbook_buys(pair_id)` | `GET .../orderbooks/{pair_id}/buys` |
| `ramzinex_get_orderbook_sells(pair_id)` | `GET .../orderbooks/{pair_id}/sells` |
| `ramzinex_get_market_buy_price(pair_id, amount2)` | `GET .../orderbooks/{pair_id}/market_buy_price` |
| `ramzinex_get_market_sell_price(pair_id, amount)` | `GET .../orderbooks/{pair_id}/market_sell_price` |
| `ramzinex_get_prices` | `GET /exchange/api/exchange/prices` |
| `ramzinex_get_currencies` | `GET .../currencies` |
| `ramzinex_get_networks(currency_id?, withdraw?, deposit?)` | `GET .../networks` |

### Auth & access management — private

| Tool | Endpoint | Notes |
| --- | --- | --- |
| `ramzinex_authenticate` | `POST .../auth/api_key/getToken` | Runs the api_key+secret login flow; caches the token (never returns it). |
| `ramzinex_edit_general_access(address_free, alert)` | `POST .../auth/api_key/editGeneralAccess` | ⚠️ gated by `account_control` |
| `ramzinex_edit_private_access(api_key_id, withdraw, trade, cancel, excel, ip_free, ips?)` | `POST .../auth/api_key/editPrivateAccess` | ⚠️ gated by `account_control` |

### Orders — private

| Tool | Endpoint | Notes |
| --- | --- | --- |
| `ramzinex_get_orders(limit, offset, types, pairs, currencies, states, is_buy)` | `POST .../users/me/orders2` | read-only |
| `ramzinex_get_order(order_id)` | `GET .../users/me/orders2/{order_id}` | read-only |
| `ramzinex_place_limit_order(pair_id, amount, price, type)` | `POST .../users/me/orders/limit` | ⚠️ gated by `enable_trading` |
| `ramzinex_place_market_order(pair_id, amount, type)` | `POST .../users/me/orders/market` | ⚠️ gated by `enable_trading` |
| `ramzinex_cancel_order(order_id)` | `POST .../users/me/orders/{order_id}/cancel` | ⚠️ gated by `enable_trading` |
| `ramzinex_get_turnover(days=30)` | `GET .../users/me/orders/turnover` | read-only |

### Funds — private

| Tool | Endpoint |
| --- | --- |
| `ramzinex_get_funds` | `GET .../users/me/funds/details` |
| `ramzinex_get_currency_fund(currency_id)` | `GET .../funds/details/currency/{currency_id}` |
| `ramzinex_get_balance_summary` | `GET .../users/me/funds/summaryDesktop` |
| `ramzinex_get_total_balance(currency_id)` | `GET .../funds/total/currency/{currency_id}` |
| `ramzinex_get_available_balance(currency_id)` | `GET .../funds/available/currency/{currency_id}` |
| `ramzinex_get_in_orders_balance(currency_id)` | `GET .../funds/in_orders/currency/{currency_id}` |
| `ramzinex_get_rial_equivalent` | `GET .../users/me/funds/rial_equivalent` |
| `ramzinex_get_usdt_equivalent` | `GET .../users/me/funds/usdt_equivalent` |
| `ramzinex_refresh_funds` | `POST .../users/me/funds/refresh` |

### Wallet (deposits / withdrawals / addresses) — private

| Tool | Endpoint | Notes |
| --- | --- | --- |
| `ramzinex_get_addresses(networks)` | `POST .../users/me/addresses` | read-only |
| `ramzinex_allocate_address(network_id, currency_id?)` | `POST .../users/me/addresses/generate` | ⚠️ gated by `enable_withdrawals`; best-effort path (confirm against panel) |
| `ramzinex_get_deposits(limit, offset)` | `GET .../funds/deposits` | read-only |
| `ramzinex_get_currency_deposits(currency_id, limit, offset)` | `GET .../funds/deposits/currency/{currency_id}` | read-only |
| `ramzinex_get_deposit(deposit_id)` | `GET .../funds/deposits/{deposit_id}` | read-only |
| `ramzinex_refresh_deposits(currency_id)` | `POST .../funds/deposits/refresh/currency/{currency_id}` | refresh (no funds moved) |
| `ramzinex_get_withdraws(limit, offset, currency_id?)` | `GET .../funds/withdraws` | read-only |
| `ramzinex_get_currency_withdraws(currency_id)` | `GET .../funds/withdraws/currency/{currency_id}` | read-only |
| `ramzinex_get_withdraw(withdraw_id)` | `GET .../funds/withdraws/{withdraw_id}` | read-only |
| `ramzinex_submit_withdraw(currency_id, amount, address, network_id, tag?)` | `POST .../funds/withdraws/currency/{currency_id}` | ⚠️ gated by `enable_withdrawals` |
| `ramzinex_confirm_withdraw(withdraw_id, code, ga_code)` | `POST .../funds/withdraws/{withdraw_id}/verify` | ⚠️ gated by `enable_withdrawals` |

### Rewards & commissions — private

| Tool | Endpoint | Notes |
| --- | --- | --- |
| `ramzinex_get_rewards` | `GET .../users/me/rewards` | read-only; best-effort path (confirm against panel) |
| `ramzinex_get_commissions` | `GET .../users/me/commissions` | read-only; best-effort path (confirm against panel) |

### Meta

| Tool | Description |
| --- | --- |
| `healthcheck` | Pings the public pairs endpoint and reports reachability. |
| `list_instances` | Lists configured instances (base URLs, `api_version`, `auth_header_name`, `has_credentials`, `auth_method`, `enable_trading`, `enable_withdrawals`, `account_control`, `read_only`) — never credential values. |
| `ramzinex_docs(topic?)` | Offline reference + links to https://ramzinex.com/exchange/apidocs. |


> All endpoints at a glance, grouped by category:

![endpoint-map](assets/diagrams/endpoint-map.png)

## API coverage

Every section/endpoint of the official Postman collection maps to a tool. The
`source` column is `postman` for items present in the collection text and
`best-effort` for the three tools whose exact URLs the pasted collection did not
include (rewards, commissions, and deposit-address allocation) — **confirm those
against the Ramzinex panel/Postman**.

| Postman section / endpoint | Method | Path | Tool | Source |
| --- | --- | --- | --- | --- |
| Market — pairs | GET | `/.../exchange/pairs` | `ramzinex_get_pairs` | postman |
| Market — pair | GET | `/.../exchange/pairs/{id}` | `ramzinex_get_pair` | postman |
| Market — orderbook | GET | `/.../orderbooks/{id}/buys_sells` | `ramzinex_get_orderbook` | postman |
| Market — all orderbooks | GET | `/.../orderbooks/buys_sells` | `ramzinex_get_all_orderbooks` | postman |
| Market — orderbook buys | GET | `/.../orderbooks/{id}/buys` | `ramzinex_get_orderbook_buys` | postman |
| Market — orderbook sells | GET | `/.../orderbooks/{id}/sells` | `ramzinex_get_orderbook_sells` | postman |
| Market — market buy price | GET | `/.../orderbooks/{id}/market_buy_price` | `ramzinex_get_market_buy_price` | postman |
| Market — market sell price | GET | `/.../orderbooks/{id}/market_sell_price` | `ramzinex_get_market_sell_price` | postman |
| Market — prices feed | GET | `/exchange/api/exchange/prices` | `ramzinex_get_prices` | postman |
| Market — currencies | GET | `/.../exchange/currencies` | `ramzinex_get_currencies` | postman |
| Market — networks | GET | `/.../exchange/networks` | `ramzinex_get_networks` | postman |
| Auth — getToken | POST | `/.../auth/api_key/getToken` | `ramzinex_authenticate` | postman |
| Auth — editGeneralAccess | POST | `/.../auth/api_key/editGeneralAccess` | `ramzinex_edit_general_access` ⚠ | postman |
| Auth — editPrivateAccess | POST | `/.../auth/api_key/editPrivateAccess` | `ramzinex_edit_private_access` ⚠ | postman |
| Orders — list | POST | `/.../users/me/orders2` | `ramzinex_get_orders` | postman |
| Orders — get | GET | `/.../users/me/orders2/{id}` | `ramzinex_get_order` | postman |
| Orders — limit | POST | `/.../users/me/orders/limit` | `ramzinex_place_limit_order` ⚠ | postman |
| Orders — market | POST | `/.../users/me/orders/market` | `ramzinex_place_market_order` ⚠ | postman |
| Orders — cancel | POST | `/.../users/me/orders/{id}/cancel` | `ramzinex_cancel_order` ⚠ | postman |
| Orders — turnover | GET | `/.../users/me/orders/turnover` | `ramzinex_get_turnover` | postman |
| Funds — details | GET | `/.../users/me/funds/details` | `ramzinex_get_funds` | postman |
| Funds — currency detail | GET | `/.../funds/details/currency/{id}` | `ramzinex_get_currency_fund` | postman |
| Funds — summaryDesktop | GET | `/.../funds/summaryDesktop` | `ramzinex_get_balance_summary` | postman |
| Funds — total | GET | `/.../funds/total/currency/{id}` | `ramzinex_get_total_balance` | postman |
| Funds — available | GET | `/.../funds/available/currency/{id}` | `ramzinex_get_available_balance` | postman |
| Funds — in_orders | GET | `/.../funds/in_orders/currency/{id}` | `ramzinex_get_in_orders_balance` | postman |
| Funds — rial equivalent | GET | `/.../funds/rial_equivalent` | `ramzinex_get_rial_equivalent` | postman |
| Funds — usdt equivalent | GET | `/.../funds/usdt_equivalent` | `ramzinex_get_usdt_equivalent` | postman |
| Funds — refresh | POST | `/.../funds/refresh` | `ramzinex_refresh_funds` | postman |
| Wallet — addresses | POST | `/.../users/me/addresses` | `ramzinex_get_addresses` | postman |
| Wallet — allocate address | POST | `/.../users/me/addresses/generate` | `ramzinex_allocate_address` ⚠ | best-effort |
| Wallet — deposits | GET | `/.../funds/deposits` | `ramzinex_get_deposits` | postman |
| Wallet — currency deposits | GET | `/.../funds/deposits/currency/{id}` | `ramzinex_get_currency_deposits` | postman |
| Wallet — deposit | GET | `/.../funds/deposits/{id}` | `ramzinex_get_deposit` | postman |
| Wallet — refresh deposits | POST | `/.../funds/deposits/refresh/currency/{id}` | `ramzinex_refresh_deposits` | postman |
| Wallet — withdraws | GET | `/.../funds/withdraws` | `ramzinex_get_withdraws` | postman |
| Wallet — currency withdraws | GET | `/.../funds/withdraws/currency/{id}` | `ramzinex_get_currency_withdraws` | postman |
| Wallet — withdraw | GET | `/.../funds/withdraws/{id}` | `ramzinex_get_withdraw` | postman |
| Wallet — submit withdraw | POST | `/.../funds/withdraws/currency/{id}` | `ramzinex_submit_withdraw` ⚠ | postman |
| Wallet — confirm withdraw | POST | `/.../funds/withdraws/{id}/verify` | `ramzinex_confirm_withdraw` ⚠ | postman |
| Rewards — rewards | GET | `/.../users/me/rewards` | `ramzinex_get_rewards` | best-effort |
| Rewards — commissions | GET | `/.../users/me/commissions` | `ramzinex_get_commissions` | best-effort |
| Meta — reachability | GET | `/.../exchange/pairs` | `healthcheck` | local |
| Meta — instances | – | (local) | `list_instances` | local |
| Meta — docs | – | (local) | `ramzinex_docs` | local |

⚠ = money-moving or account-control; gated by `enable_trading` /
`enable_withdrawals` / `account_control` (all forced off by `read_only`).

## Prompts

The server also ships MCP **prompts** — safety-aware workflows your client can
list and run (details in [`prompts/README.md`](prompts/README.md)):

- **`market_overview`** — pull pairs + an orderbook and summarize the market.
- **`check_balances`** — walk the funds/balance tools to report holdings.
- **`place_trade_safely`** — a careful checklist that verifies `enable_trading`
  and confirms parameters before placing a REAL order.
- **`portfolio_report`** — combine funds + open orders + turnover.

## Skill

A ready-to-use Claude/agent skill lives at
[`skills/ramzinex/SKILL.md`](skills/ramzinex/SKILL.md). It describes when and how
to use these tools — market lookup, balance checks, and the safe trading flow —
with example tool sequences.

## Architecture

The MCP client talks to one `ramzinex-mcp` process, which routes public calls to
`publicapi.ramzinex.com` and authenticated calls (with the `Authorization2` +
`x-api-key` headers) to `ramzinex.com`.

![architecture](assets/diagrams/architecture.png)

One process can serve many accounts; the `instance` argument selects which token
/ trading policy to use.

![self-hosting](assets/diagrams/self-hosting-multi-instance.png)

A typical flow: read the market on the public API, check the `enable_trading`
gate, then place and confirm an order on the private API.

![request-flow](assets/diagrams/request-flow.png)

Regenerate the diagrams with `make diagrams` (uses the `diagrams` package +
Graphviz `dot` and `cairosvg`).

## Self-hosting & scaling

`ramzinex-mcp` is stateless, so you can run as many replicas as you like behind a
load balancer. One process fronts multiple accounts via
`RAMZINEX__INSTANCES__<NAME>__*` — no code change. Back off on HTTP 429 if the
exchange rate-limits you. See [`deploy/`](deploy/) for Docker Compose,
Kubernetes (raw + Kustomize), a Helm chart, and a Terraform module.

## Testing

```bash
make smoke          # no-network smoke test (tools + prompts + descriptions)
make test           # full pytest suite (offline; all HTTP mocked with respx)
make lint           # ruff
```

Live tests against the real API are skipped unless `RAMZINEX_LIVE=1` is set (and,
for private endpoints, `RAMZINEX_API_TOKEN`):

```bash
RAMZINEX_LIVE=1 pytest tests/live -q
```

## License

[MIT](LICENSE). `ramzinex-mcp` is an unofficial, community-built integration; the
Ramzinex name and logo belong to their owner.

<div align="center">
  <img src="assets/icons/ramzinex.svg" alt="" height="100" align="absmiddle" />
</div>

TDQS

A4/5.0

Scored across 45 tools

Disambiguation5/5

Every tool has a clearly distinct purpose, targeting different resources or actions. Even similar verbs like 'get_deposits' vs 'get_currency_deposits' vs 'get_deposit' are differentiated by scope and granularity. No two tools overlap in functionality.

Naming Consistency5/5

All tools follow the 'ramzinex_[verb]_[noun(s)]' pattern with consistent snake_case. Verbs are uniformly lowercase and descriptive (get, list, place, cancel, submit, confirm, edit, allocate). No mixing of conventions or inconsistent naming styles.

Tool Count4/5

45 tools is high but justified given the comprehensive exchange API surface. The count slightly exceeds the typical 'well-scoped' range, yet each tool corresponds to a meaningful endpoint. A few get tools could potentially be merged, but overall the count is reasonable for a full-featured exchange MCP.

Completeness5/5

The tool set covers the full lifecycle: public market data, account balances (summary, individual, locked), deposits and withdrawals (list, get, refresh, submit, confirm), orders (list, get, place limit/market, cancel), API key management, and account control. No obvious gaps for core trading and wallet operations.

Maintenance

ActivityInactive
ResponsivenessNo issues