max-mcp
by bistin
README.md
# max-mcp
[](https://github.com/bistin/max-mcp-server/actions/workflows/test.yml)
[](./LICENSE)
An [MCP](https://modelcontextprotocol.io) server for the
[MAX Exchange](https://max.maicoin.com/) (MaiCoin) V3 REST API.
> **Disclaimer.** Unofficial and community-maintained. Not affiliated with,
> endorsed by, or supported by MaiCoin / MAX Exchange. Trading tools move real
> funds — use at your own risk.
It exposes MAX endpoints as MCP tools so an agent (Claude Code, Claude Desktop,
etc.) can query market data, read your account, and — when explicitly enabled —
place and cancel orders. The request signing follows the MAX V3 auth scheme:
HMAC-SHA256 over a base64 JSON payload, with the nonce echoed in the query/body
and `path` matched exactly (see [`max_mcp/client.py`](max_mcp/client.py)).
## Tools
| Group | Needs | Tools |
|-------|-------|-------|
| Public market data | — | `get_markets`, `get_currencies`, `get_server_timestamp`, `calibrate_time`, `get_ticker`, `get_tickers`, `get_order_book`, `get_klines`, `get_public_trades`, `get_index_prices`, `get_historical_index_prices`, `get_borrowing_interest_rates`, `get_borrowing_limits` |
| Account / history (read) | API key+secret | `get_user_info`, `get_accounts`, `get_order`, `get_open_orders`, `get_closed_orders`, `get_order_history`, `get_order_trades`, `get_my_trades`, `get_deposits`, `get_deposit`, `get_deposit_address`, `get_withdrawals`, `get_withdrawal`, `get_withdraw_addresses`, `get_rewards`, `get_internal_transfers`, `get_converts`, `get_convert` |
| M-Wallet (read) | API key+secret | `get_ad_ratio`, `get_loans`, `get_interests`, `get_liquidations` |
| Trading + m-wallet (**write**) | API key+secret **and** `MAX_ENABLE_TRADING` | `create_order`, `cancel_order`, `cancel_all_orders`, `create_loan`, `repay_loan`, `m_transfer` |
Write tools are **not registered at all** unless `MAX_ENABLE_TRADING` is set, so
an agent can't even see them in the default read-only configuration.
## Configuration (environment variables)
| Variable | Required for | Notes |
|----------|--------------|-------|
| `MAX_API_KEY` | private endpoints | your MAX API access key |
| `MAX_API_SECRET` | private endpoints | your MAX API secret key |
| `MAX_ENABLE_TRADING` | write tools | set to `1`/`true`/`yes` to register order/loan/transfer tools |
| `MAX_API_BASE_URL` | — | override base URL (default `https://max-api.maicoin.com`) |
Public market-data tools work with no credentials.
## Install
The package installs a `max-mcp` console script. The tricky part is **where that
binary lives**: an MCP client (Claude Code / Desktop) launches a fresh process
that does *not* inherit your shell's `PATH` or any activated virtualenv. So the
reliable pattern is to either let `uv` resolve the environment for you, or point
the client at an **absolute path** to the binary. Pick one of the options below.
### Option A — uv (recommended, no install step)
[uv](https://docs.astral.sh/uv/) can run the server straight from GitHub and
manage the environment itself, so there's no `PATH` to worry about:
```bash
# one-off smoke test
uvx --from "git+https://github.com/bistin/max-mcp-server.git" max-mcp
```
`uvx` is the command the MCP client will run too (see config sections below),
which sidesteps the whole "is it on my PATH" problem.
For local development with uv:
```bash
git clone https://github.com/bistin/max-mcp-server.git
cd max-mcp-server
uv sync # creates .venv and installs the project + deps
uv run max-mcp # runs the stdio server inside the managed env
```
### Option B — venv + pip
Standard library virtualenv, no extra tooling:
```bash
git clone https://github.com/bistin/max-mcp-server.git
cd max-mcp-server
python3 -m venv .venv
.venv/bin/pip install -e .
.venv/bin/max-mcp # run via the venv's binary, not a bare `max-mcp`
```
The venv's binary lives at `/abs/path/to/max-mcp-server/.venv/bin/max-mcp`
(`...\.venv\Scripts\max-mcp.exe` on Windows). Note that path — you'll give it to
the MCP client below. Activating the venv (`source .venv/bin/activate`) only
affects *your* shell, not the client process, so don't rely on a bare `max-mcp`
working there.
> **Tip:** run `command -v max-mcp` (or `.venv/bin/python -c "import shutil,sys;
> print(shutil.which('max-mcp'))"`) to print the absolute path to paste into the
> configs below.
## Register with Claude Code
With uv (Option A) — no install step, uv resolves the env each launch:
```bash
claude mcp add max \
-e MAX_API_KEY=your_key \
-e MAX_API_SECRET=your_secret \
-- uvx --from "git+https://github.com/bistin/max-mcp-server.git" max-mcp
```
With a venv (Option B) — point at the venv's absolute binary path:
```bash
claude mcp add max \
-e MAX_API_KEY=your_key \
-e MAX_API_SECRET=your_secret \
-- /abs/path/to/max-mcp-server/.venv/bin/max-mcp
```
Add `-e MAX_ENABLE_TRADING=1` only if you want the agent to place/cancel orders.
## Claude Desktop config
Claude Desktop launches the command itself, so the same rule applies: use `uvx`,
or give an absolute path. Pick the block that matches your install.
uv (Option A):
```json
{
"mcpServers": {
"max": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/bistin/max-mcp-server.git",
"max-mcp"
],
"env": {
"MAX_API_KEY": "your_key",
"MAX_API_SECRET": "your_secret"
}
}
}
}
```
venv (Option B) — use the absolute path to the venv binary
(`...\.venv\Scripts\max-mcp.exe` on Windows):
```json
{
"mcpServers": {
"max": {
"command": "/abs/path/to/max-mcp-server/.venv/bin/max-mcp",
"env": {
"MAX_API_KEY": "your_key",
"MAX_API_SECRET": "your_secret"
}
}
}
}
```
## Tests
With uv:
```bash
uv run --extra test pytest
```
With a venv:
```bash
.venv/bin/pip install -e ".[test]"
.venv/bin/python -m pytest
```
All HTTP is mocked with `respx`, so the suite never touches the live API or your
account — it's safe to run with real credentials in the environment. The 44
tests cover:
- **Signing/headers** — nonce in both query and payload, `path` match, HMAC
signature, monotonic nonce under same-millisecond concurrency.
- **Request placement** — GET params in the query string vs POST/DELETE params
in the JSON body; `None`-valued optionals dropped, never sent as `null`.
- **Tool gating** — write tools hidden unless `MAX_ENABLE_TRADING`; flag parsing
of `1`/`true`/`yes` (case-insensitive).
- **Edge cases** — `markets[]` array params repeated correctly, the
`cancel_all_orders` safety scope, `calibrate_time` propagating upstream errors
instead of crashing, error/network-failure mapping to a structured dict, and
the console entry point.
## Notes
- All prices/volumes/fees/balances are returned as **strings** — keep them as
decimal strings, never parse to float.
- K-lines return bare numeric arrays `[ts, o, h, l, c, v]` with unix-second
timestamps.
- MAX API errors are returned as `{"_http_status": <int>, "success": false,
"error": {"code", "message"}}` so the agent can read the code/message.
## License
[Apache-2.0](./LICENSE) © bistin
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues