ramzinex-mcp
<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.**
[](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/ci.yml)
[](https://github.com/ramzinex-mcp/ramzinex-mcp/actions/workflows/docker.yml)
[](https://www.python.org/)
[](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" />
</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`:

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

## 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):

## 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:

## 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:

## 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`.

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

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.

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
Scored across 45 tools
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.
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.
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.
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.