# Quickstart (/docs)
Market data works with **no API key**. Add one later if you want the assistant
to read your own account.
## Install [#install]
Pick your client. The base install serves market data; tick **+ Account/Trade**
to add your API key to the command.
### Install uv [#install-uv]
The copyable commands launch the server with `uvx`, part of
[`uv`](https://docs.astral.sh/uv/):
Check that the server resolves:
```bash
uvx delta-exchange-mcp --help
```
## Verify it works [#verify-it-works]
Restart your client and send a prompt that needs no key:
```text
Using the Delta Exchange tools, show the current BTCUSD ticker: last price,
24h change, and funding rate.
```
## Add an API key [#add-an-api-key]
Create a key with the **Read Data** permission under
[Account → API Keys](https://www.delta.exchange/app/account/manageapikeys)
(walkthrough in [Authentication](/docs/authentication)). Tick
**+ Account/Trade** above, type the key and secret straight into the command,
and restart your client: account tools such as `get_positions` appear in the
tool list.
```text
List my open positions on Delta and their unrealised PnL.
```
Or set the key once for every client on the machine instead of per client:
```bash
uvx delta-exchange-mcp login
```
That prompts with the input hidden, checks the key with Delta before saving, and
writes `~/.delta-exchange-mcp/config.env`, which every MCP client reads. Leave
the two slots above empty if you do. [Authentication](/docs/authentication)
covers both routes, and the one that works from inside the chat.
## Place orders [#place-orders]
Use a key with the **Trading** permission instead, which Delta requires an IP
whitelist for. Nothing else changes: the same install, the same tool list, and
orders go through from the moment that key is saved.
```text
Place a reduce-only limit sell of 1 BTCUSD contract at 90000.
```
The key is the only gate. There is no rehearsal, no size cap and no confirmation
step, and orders are sized in contracts rather than coins. Use
`DELTA_MCP_ENV=india_testnet` to practise. See
[Trading tools](/docs/tools/trading) and [Security](/docs/security).
Next: browse the [Use Cases](/docs/use-cases) or the full
[Tool Reference](/docs/tools). New to MCP? Start with
[What is MCP?](/docs/what-is-mcp)
Output is generated by an AI model and can be inaccurate, incomplete, or
non-deterministic. It is **not investment advice**. Trading crypto derivatives
involves substantial risk. Delta Exchange is registered with the Financial
Intelligence Unit (FIU), Govt. of India.
# What is MCP? (/docs/what-is-mcp)
The **Model Context Protocol (MCP)** is an open standard for connecting AI
applications to external tools and data through one uniform interface. Think of it as a **USB-C port for AI**: instead of every
app inventing its own integration, any MCP-compatible client can plug into any
MCP server and immediately use what it offers. The protocol is documented at
[modelcontextprotocol.io](https://modelcontextprotocol.io).
The Delta Exchange MCP server is one such server. It exposes Delta's market data,
your account data and trading as MCP tools, so any compatible AI client can use
it in plain language.
## The three pieces [#the-three-pieces]
An MCP setup is always three parts:
1. **Client (host):** the AI application you already use, such as Claude Desktop,
Cursor, or Claude Code. It holds the model and decides when to call a tool.
2. **Server:** a small program that advertises a set of tools and answers calls.
Here that is `delta-exchange-mcp`.
3. **Upstream resource:** whatever the server talks to. Here that is Delta
Exchange's REST API.
```mermaid
flowchart LR
subgraph local["Your machine"]
direction TB
client["AI client
(Claude Desktop, Cursor, Claude Code)"]
server["delta-exchange-mcp
local subprocess
reads keys from local env"]
end
api["Delta Exchange API
(market + account data)"]
client -- "MCP over stdio
tool calls + results" --> server
server -- "HTTPS, HMAC-signed
bounded by your key permission" --> api
api -- "JSON" --> server
```
The client and server speak MCP to each other; the server speaks Delta's normal
HTTPS API to Delta. Your credentials are used only on that last hop, from your
machine to Delta. They never reach the model.
## Tools, and who decides to call them [#tools-and-who-decides-to-call-them]
A server advertises **tools**: named operations with typed parameters, like
`get_ticker(symbol)` or `get_positions(...)`. You almost never name a tool
yourself. You ask a question in plain language ("what's BTC funding right now?"),
the model picks the right tool and arguments, the server runs it, and the model
reads the result back and answers you.
That is why the same Delta server works identically across every client: the
tools are the contract, and each client wires them to its own model.
The tool names and parameters in the [Tool Reference](/docs/tools) are there for
when you build agents or want to know exactly what runs. For everyday use, you
just ask.
## How this server connects [#how-this-server-connects]
The Delta Exchange server runs locally:
* It runs as a **subprocess on your own machine** and talks to your client over
stdio. It is not a hosted service.
* Your API key and secret are read from your **local environment** at launch and
used only to sign requests sent directly to Delta's API.
* They **never** pass through the AI model or any Delta server beyond the normal
trading API.
See [Security](/docs/security) for the full data-flow and key model.
## Why MCP for trading [#why-mcp-for-trading]
* **Ask, don't integrate.** Get live market and account data in plain language,
with no glue code, SDK wiring, or dashboards to build.
* **Write once, use everywhere.** One server works across every MCP client, so a
prompt that works in Claude Desktop works in Cursor or Claude Code too.
* **No key, no account.** With no credentials every tool is a read-only `GET`
against public market data. A key registers the account and trading tools, and
the key's own permission decides what they may do. The server never has a
withdrawal path.
* **Keys stay local.** Credentials are held by whatever installed the server —
the bundle's own settings, your editor's secret storage, or your client config
— and used only on your machine. Nothing sensitive flows to the model.
* **Composable.** Drop the same tools into an agent, a notebook, or a scheduled
job for monitoring, P\&L, and reconciliation.
## Supported clients [#supported-clients]
The server works with any MCP-compatible client, including **Claude Desktop,
Codex, Claude Code, Cursor, OpenClaw, Antigravity, Grok Build**, and more.
Per-client setup is in the [Quickstart](/docs).
Output is generated by an AI model and can be inaccurate, incomplete, or
non-deterministic. It is **not investment advice**. Trading crypto derivatives
involves substantial risk. Delta Exchange is registered with the Financial
Intelligence Unit (FIU), Govt. of India.
# Use Cases (/docs/use-cases)
Copy-paste prompts that show what the server can do. Paste any block into
Claude, Cursor, Claude Code, or any MCP client that has the Delta Exchange
server installed.
Market-data prompts work with **no API key**. Prompts that read your account
(positions, balances, fills) need a **Read Data** key. The trading prompts at the
end need a key with **Trading** permission (see
[Authentication](/docs/authentication)).
## Daily portfolio check-in [#daily-portfolio-check-in]
Your morning brief in one message. The core habit.
```text
Give me my Delta morning brief: open positions, unrealised PnL per position,
total exposure, and the position that moved most since yesterday. One short
paragraph, then a table.
```
**Tools:** `get_positions`, `get_margined_positions`, `get_ticker` · **Key required**
## Funding & basis monitor [#funding--basis-monitor]
For perp traders watching carry. Time-sensitive.
```text
For BTCUSD and ETHUSD perpetuals, show the current funding rate, the last 8h of
funding history, and the basis vs spot. Flag anything unusual.
```
**Tools:** `get_ticker`, `get_funding_history`, `get_indices` · **No key**
## Pre-trade research [#pre-trade-research]
Analysis before you commit. Pair it with the trading prompts below once you've
decided.
```text
I'm considering a BTC position. Show orderbook depth at the top 5 levels,
current open interest, recent trades, and the 24h range. Summarise liquidity
and where the book is heavy.
```
**Tools:** `get_orderbook`, `get_oi_history`, `get_recent_trades`, `get_candles` · **No key**
## Options chain scan [#options-chain-scan]
```text
Pull the BTC options chain for the nearest expiry. Summarise IV by strike,
highlight the highest-OI strikes, and show the put/call OI skew.
```
**Tools:** `get_options_chain`, `get_product` · **No key**
## Risk & liquidation scan [#risk--liquidation-scan]
Returns its value during volatility. Numbers only, no advice.
```text
Across all my open positions, compute margin usage and the approximate distance
to liquidation for each. Rank by risk. Just the numbers.
```
**Tools:** `get_margined_positions`, `get_positions`, `get_product_leverage` · **Key required**
## P\&L & tax history [#pl--tax-history]
Recurring, India-relevant. Hand the output to your accountant.
```text
List my fills and realised PnL for the last 30 days, grouped by symbol. Give me
a total realised PnL figure I can hand to my accountant, then export the full
fills to a CSV.
```
**Tools:** `get_fills`, `get_order_history`, `bulk_fills_export` · **Key required**
`get_fills` and `bulk_fills_export` return only the **last \~90 days** when no
start time is given. For a tax year or any older history, state the explicit
range in your prompt (e.g. "from 1 Jan 2026 to 31 Mar 2026") so the model passes
a `start_time_us`. Otherwise older trades are silently dropped.
## Market snapshot [#market-snapshot]
Lightweight, daily, no key needed.
```text
Give me a one-screen snapshot of Delta's top perpetuals: last price, 24h change,
open interest, and funding. Sorted by 24h volume.
```
**Tools:** `list_tickers`, `list_products`, `get_ticker` · **No key**
## Expiry & settlement reconciliation [#expiry--settlement-reconciliation]
After an expiry, reconcile what settled against your trades.
```text
List the BTC and ETH options/futures that settled in the last 7 days with their
settlement prices, then match them against my fills so I can reconcile realised
PnL on expired contracts.
```
**Tools:** `get_settlement_prices`, `get_fills`, `get_order_history` · **Key required**
## Wallet ledger [#wallet-ledger]
Trace cash flows: deposits, funding, commissions, settlements.
```text
Show my wallet transactions for the last 30 days grouped by type (deposits,
funding, commissions, settlements). Give me the net change per asset.
```
**Tools:** `get_wallet_transactions`, `get_wallet_balances` · **Key required**
## Trading [#trading]
These place and change real orders. They are listed with any key, and go through
only when that key carries **Trading** permission. See [Trading tools](/docs/tools/trading).
There is no rehearsal step and no confirmation prompt: the order goes as sent.
Run them against `india_testnet` with a demo key before you run them for real.
### Place an order with a bracket [#place-an-order-with-a-bracket]
```text
Place a GTC limit buy of 5 ETHUSD at 3400 with a take-profit at 3600 and a
stop-loss at 3250.
```
**Tools:** `place_order` · **Trading key**
### Bracket an open position [#bracket-an-open-position]
```text
On my open BTCUSD position, attach a stop-loss at 68000 and a take-profit at
75000.
```
**Tools:** `get_margined_positions`, `place_bracket_order` · **Trading key**
### Cancel or flatten [#cancel-or-flatten]
```text
Show my open BTCUSD orders, then cancel all of them on that product only.
```
**Tools:** `get_open_orders`, `cancel_all_orders` · **Trading key**
### Adjust leverage and margin [#adjust-leverage-and-margin]
```text
Set my BTCUSD order leverage to 10x and add 5 USDT of isolated margin to the
position.
```
**Tools:** `set_product_leverage`, `adjust_position_margin` · **Trading key**
***
The read-only prompts above read data only. The trading prompts place orders on
your instruction and your responsibility, with no rehearsal step in between.
Output is generated by an AI model. It can be inaccurate, incomplete, or
non-deterministic, and is **not investment advice**. Verify against the official
Delta Exchange app before acting.
# Authentication (/docs/authentication)
The server authenticates to Delta's API with an **API key + secret**. You
never paste credentials into the AI model. They are
supplied once at install time — through the bundle's form, your editor's masked
prompt, or your client's config file — and read into the server at startup.
From v0.6.0 there is a second place they can live: one file the server keeps for
every client on the machine. [Where the key goes](#where-the-key-goes) below
covers both, and which one wins when you use both.
## Which tools need what [#which-tools-need-what]
| Group | Key required | Examples |
| ------------ | ------------------------------------------ | --------------------------------------------------------------------------- |
| Setup | No | `setup_credentials`, `get_connection_status` |
| Market data | No | `get_ticker`, `get_orderbook`, `get_candles`, `get_options_chain` |
| Account data | Yes | `get_positions`, `get_wallet_balances`, `get_fills`, `bulk_fills_export` |
| Trading | Yes, and **Trading** permission to execute | `place_order`, `cancel_order`, `place_bracket_order`, `close_all_positions` |
If you only want market data, skip key creation entirely. For account reads, a
**Read Data** key is enough. Create a **Trading** key only if you want the
assistant placing orders.
A key registers the account and trading tools together, so the tool list your
client displays tells you whether credentials arrived, not what they may do:
| What you configured | Tools registered |
| ------------------------------ | ---------------------------------------- |
| Nothing | Setup and market data |
| A valid key, either permission | Setup, market data, account, and trading |
The trading tools are listed with a Read Data key as well. Delta rejects what
they send with `Unauthorized`, and the server says the key lacks Trading
permission.
`DELTA_MCP_DEBUG` adds one more tool in either case,
`get_debug_status`, which reports where the
[debug log](/docs/troubleshooting#capture-a-debug-log) is being written.
## Create your API key [#create-your-api-key]
### Open API key management [#open-api-key-management]
Go to **delta.exchange → Account → Manage API Keys**.
### Choose permissions for your use [#choose-permissions-for-your-use]
For data only, enable **Read Data** and nothing else. That also limits the blast
radius if the key ever leaks. To let the assistant place orders, enable
**Trading**. Grant only what you need.
### Whitelist your IP [#whitelist-your-ip]
Add an IP whitelist so the key only works from your machine. This is
**required** for a Trading key to work. You can revoke the key anytime from the
same page; revocation is immediate.
### Hand the key to the server [#hand-the-key-to-the-server]
If you installed the Claude Desktop bundle, type the key and secret into its
install form. In VS Code, paste them at the masked prompt. Everywhere else, set
them as environment variables in your client's MCP config. All three routes are
covered in the [Quickstart](/docs). Or put the key in the shared file below and
leave your client's config without credentials at all.
## Where the key goes [#where-the-key-goes]
There are two places a key can live, and they are read in a fixed order.
**Your client's own config** is read first: the bundle's install form, VS Code's
masked prompt, or an `env` block in a config file. This is what the install
builder fills in when you type a key into it.
**The shared file** is read second:
```
~/.delta-exchange-mcp/config.env
```
Every MCP client on the machine reads it, so a key set there works in Claude
Desktop, Cursor, Claude Code and the rest at the same time. The server creates
the file the first time it runs, owner-only, with instructions inside it, and
prints the path in its startup line.
A value your client sets always wins. Leaving a field empty in your client means
"not answered" and falls through to the file. Getting this backwards is a real
failure mode with a confusing symptom, so it has [its own troubleshooting
entry](/docs/troubleshooting#the-form-saved-my-key-but-the-assistant-still-cannot-see-my-account).
### Three ways to fill the shared file [#three-ways-to-fill-the-shared-file]
All three write the same file. Pick one.
**In the conversation.** Ask your assistant to connect your account and a form
appears inline:
```text
Connect my Delta Exchange account
```
It asks which site the key came from, what the assistant may do with it, then the
key and the secret. What you type goes straight to the file. It is not part of
the conversation and the assistant cannot read it, because the form runs in its
own frame. This needs a client that renders in-chat forms: Claude Desktop and the
Codex desktop app do today. On any other client nothing appears and you get the
instructions instead. See [`setup_credentials`](/docs/tools/setup).
**At a terminal**, which works on every client:
```bash
uvx delta-exchange-mcp login
```
It prompts with the input hidden and checks the key against Delta before saving
anything.
**By hand.** Open the file and fill in the three lines already waiting in it:
```dotenv
DELTA_API_KEY=your-key-here
DELTA_API_SECRET=your-secret-here
DELTA_MCP_ENV=india_prod
```
The form exists so the key stays out of the conversation. A message is in the
assistant's context and is stored in the conversation. If an assistant offers to
take your key that way, decline.
The terminal and by-hand routes normally need your client restarted afterwards.
The in-chat form usually needs neither: a saved key registers the account and
trading tools in the running server and tells the client its tool list changed,
so first-time setup, environment changes and key rotation need no restart of the
server. Some clients, Claude Desktop among them, read the tool list only when they
start the server: if the account tools do not appear, restart the client. The
trading tools follow the key, so saving one that carries Trading permission arms
them too.
## Choosing the key permission [#choosing-the-key-permission]
The permission on the key decides whether the assistant can trade. No setting
here changes that, and
[Security](/docs/security#your-keys-permission-is-the-only-gate) explains why it
is the boundary that holds.
Grant **Read Data** and the assistant reads your account while Delta rejects
every order it sends. Grant **Trading** and it places real orders from the moment
the key is saved, with no rehearsal, no size cap and no confirmation step. Delta
requires an IP whitelist entry on a Trading key.
## Environment variables [#environment-variables]
| Variable | Required | Description |
| ---------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `DELTA_API_KEY` | For account / trading tools | Your API key. Its own permission decides what the assistant may do. |
| `DELTA_API_SECRET` | For account / trading tools | The matching secret. |
| `DELTA_MCP_ENV` | Yes | Target environment: `india_prod` (production) or `india_testnet` (testnet). |
| `DELTA_MCP_DEBUG` | No | Set `1` to trace every HTTP request and response to a file, for bug reports. See [Troubleshooting](/docs/troubleshooting#capture-a-debug-log). |
| `DELTA_MCP_DEBUG_FILE` | No | Override the debug log path (default `~/.delta-exchange-mcp/logs/`). |
A production key only works with `india_prod`; a testnet key only with
`india_testnet`. Mixing them produces signature/auth errors. Test trading on
testnet first: it is the only way to rehearse an order.
## Where your keys live [#where-your-keys-live]
Your credentials stay on your machine. Which file holds them depends on how you
installed the server:
| Install path | Where the credentials are stored |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Claude Desktop bundle | Entered in the install form; Claude Desktop keeps them with the server's own settings, not in a file you edit. |
| VS Code one-click | Entered at the masked prompt; VS Code stores them in its own secret storage and injects them via `${input:…}`, so they never land in `.vscode/mcp.json`. |
| Cursor one-click, or any hand-written config | Plain text in your client's config file — `~/.cursor/mcp.json`, `~/.codex/config.toml`, `claude_desktop_config.json`, and so on. |
| The in-chat form, `login`, or editing by hand | Plain text in `~/.delta-exchange-mcp/config.env`, created owner-only. One file for every client on the machine, read after whatever your client sets. |
Whichever path you used, the rest is the same:
* Read into the server subprocess as environment variables at launch.
* Used to sign requests sent **directly from your machine** to Delta's API,
with HMAC-SHA256.
* **Never** sent to the AI model or any Delta server beyond the trading API.
More on the security model in [Security](/docs/security).
Do not commit a config file containing real credentials to git. Treat the API
secret like a password.
# Overview (/docs/tools)
The server has four groups of tools. Market data and setup need no
key; the account and trading tools register together as soon as a key is present
(see [Trading](/docs/tools/trading)). Each tool entry lists its parameters,
whether it needs an API key, and a copy-paste example prompt.
You rarely call tools by name. You ask in plain language and the client picks
the tool. The names and parameters here are for reference and for building
agents.
## Conventions [#conventions]
* **Symbols** are Delta product symbols, e.g. `BTCUSD` (perp) or
`C-BTC-66400-010824` (option).
* **Timestamps** in candle/history tools are **Unix seconds**; in
fills/orders/wallet history they are **microseconds** (`*_us`).
* **Paginated** tools return a `meta.after` cursor; pass it back to fetch the
next page.
* **Auth badge** on each tool is the source of truth for whether a key is
needed, regardless of which group it sits in.
Tool names and parameters reflect the current server build. Run
`uvx delta-exchange-mcp` and inspect your client's tool list to confirm what
your installed version exposes.
# Market Data (/docs/tools/market-data)
All tools on this page are **public** and need **no API key**. Symbols are Delta
product symbols (e.g. `BTCUSD`). Candle/history timestamps are **Unix seconds**.
## get\_ticker [#get_ticker]
24h ticker for one symbol: last price, volume, open interest, mark and spot.
**Auth:** No key
| Param | Type | Required | Notes |
| -------- | ------ | -------- | ------------- |
| `symbol` | string | yes | e.g. `BTCUSD` |
```text
Show the BTCUSD ticker: last price, 24h change, volume, and funding rate.
```
## list\_tickers [#list_tickers]
Tickers across many products, with optional filters. Good for a market snapshot.
**Auth:** No key
| Param | Type | Required | Notes |
| -------------------------- | --------- | -------- | ------------------------------------------------------------- |
| `contract_types` | string\[] | no | `perpetual_futures`, `futures`, `call_options`, `put_options` |
| `underlying_asset_symbols` | string\[] | no | e.g. `BTC`, `ETH`, `SOL` |
```text
Snapshot the top perpetuals by 24h volume: last price, 24h change, OI, funding.
```
## get\_product [#get_product]
Full product metadata for one symbol: tick size, contract value, leverage caps.
**Auth:** No key
| Param | Type | Required | Notes |
| -------- | ------ | -------- | ------------------------------------- |
| `symbol` | string | yes | e.g. `BTCUSD` or `C-BTC-66400-010824` |
```text
Show the contract spec for BTCUSD: tick size, contract value, and max leverage.
```
## list\_products [#list_products]
Tradable products with optional filters. Paginated (returns `meta.after`).
**Auth:** No key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | --------------------------------------------------------------------- |
| `contract_types` | string\[] | no | `perpetual_futures`, `call_options`, `put_options`, `futures`, `spot` |
| `states` | string\[] | no | `live`, `upcoming`, `expired`, `settled` |
| `expiry` | string | no | `YYYY-MM-DD` (current/future expiries only) |
| `page_size` | int | no | default 100, max 500 |
| `after` | string | no | cursor from a previous response's `meta.after` |
```text
List all live perpetual futures on Delta.
```
## get\_orderbook [#get_orderbook]
L2 order book snapshot for a symbol.
**Auth:** No key
| Param | Type | Required | Notes |
| -------- | ------ | -------- | ------------------------ |
| `symbol` | string | yes | e.g. `BTCUSD` |
| `depth` | int | no | levels per side, max 100 |
```text
Show the BTCUSD order book at 10 levels per side and where the book is heavy.
```
## get\_recent\_trades [#get_recent_trades]
Recent public trades for a symbol.
**Auth:** No key
| Param | Type | Required | Notes |
| -------- | ------ | -------- | ------------- |
| `symbol` | string | yes | e.g. `BTCUSD` |
```text
Show the most recent BTCUSD trades and the buy/sell balance.
```
## get\_candles [#get_candles]
OHLC candles for a symbol over a time window.
**Auth:** No key
| Param | Type | Required | Notes |
| ------------ | ------ | -------- | ------------------------------------------------------------------ |
| `symbol` | string | yes | e.g. `BTCUSD` |
| `resolution` | string | yes | `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `1d`, `1w` |
| `start` | int | yes | Unix seconds, inclusive |
| `end` | int | yes | Unix seconds, inclusive |
```text
Pull BTCUSD 1h candles for the last 24 hours and describe the trend.
```
## get\_mark\_price\_history [#get_mark_price_history]
Historical mark-price candles: useful for P\&L curves and slippage vs fair value.
**Auth:** No key
| Param | Type | Required | Notes |
| ------------ | ------ | -------- | --------------------------------------- |
| `symbol` | string | yes | e.g. `BTCUSD` or `C-BTC-66400-010824` |
| `start` | int | yes | Unix seconds, inclusive |
| `end` | int | yes | Unix seconds, inclusive |
| `resolution` | string | no | default `1m`; same set as `get_candles` |
```text
Show BTCUSD mark price every 5m over the last 6 hours.
```
## get\_oi\_history [#get_oi_history]
Historical open-interest candles: detect positioning extremes and OI build-up.
**Auth:** No key
| Param | Type | Required | Notes |
| ------------ | ------ | -------- | --------------------------------------- |
| `symbol` | string | yes | e.g. `BTCUSD` |
| `start` | int | yes | Unix seconds, inclusive |
| `end` | int | yes | Unix seconds, inclusive |
| `resolution` | string | no | default `1h`; same set as `get_candles` |
```text
Plot BTCUSD open interest over the last 7 days and flag any sharp build-up.
```
## get\_funding\_history [#get_funding_history]
Historical funding-rate candles for a perpetual: basis analysis and realised funding.
**Auth:** No key
| Param | Type | Required | Notes |
| ------------ | ------ | -------- | --------------------------------------- |
| `symbol` | string | yes | perpetual symbol, e.g. `BTCUSD` |
| `start` | int | yes | Unix seconds, inclusive |
| `end` | int | yes | Unix seconds, inclusive |
| `resolution` | string | no | default `1h`; same set as `get_candles` |
```text
Show ETHUSD funding over the last 3 days and the cumulative funding paid by a long.
```
## get\_options\_chain [#get_options_chain]
Full call + put chain for one underlying on one expiry.
**Auth:** No key
| Param | Type | Required | Notes |
| ------------- | ------ | -------- | ---------------------------------------------------------------------------- |
| `underlying` | string | yes | e.g. `BTC`, `ETH` |
| `expiry_date` | string | yes | `DD-MM-YYYY` (note: different from `list_products`, which uses `YYYY-MM-DD`) |
```text
Pull the BTC options chain for the nearest expiry. Summarise IV by strike and
the put/call OI skew.
```
## get\_indices [#get_indices]
Spot price indices Delta builds from multiple exchanges. These underlie its
futures and options.
**Auth:** No key
No parameters.
Returns each index's constituent exchanges + weights, `index_type`
(`spot_pair` / `fixed_interest_rate` / `floating_interest_rate`), tick size, and
the underlying/quoting asset. Use to audit how a product's mark or settlement
price is built.
```text
Show the BTC spot index composition: which exchanges and weights build it.
```
## get\_settlement\_prices [#get_settlement_prices]
Settlement prices for expired/settled derivatives: post-expiry P\&L
reconciliation and backtesting. Paginated.
**Auth:** No key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ---------------------------------------------- |
| `contract_types` | string\[] | no | e.g. `call_options`, `put_options`, `futures` |
| `page_size` | int | no | default 100, max 500 |
| `after` | string | no | cursor from a previous response's `meta.after` |
Each product carries `settlement_time` and `settlement_price` alongside its
metadata. (Under the hood this is `list_products(states=["expired"])`.)
```text
List BTC options that settled in the last week with their settlement prices.
```
## get\_reference\_data [#get_reference_data]
Merged assets + indices listing: symbol and asset metadata lookups.
**Auth:** No key
No parameters. For index-only queries (composition, weights), prefer
`get_indices`.
```text
What assets and quoting currencies does Delta support?
```
# Account (/docs/tools/account)
All tools on this page need a **Read Data** API key (see
[Authentication](/docs/authentication)). They are read-only; none can place,
modify, or cancel orders or move funds. Fills/orders/wallet timestamps are
**microseconds** (`*_us`); paginated tools return a `meta.after` cursor.
## get\_positions [#get_positions]
Open position(s), lightweight. Returns `entry_price` and `size` only.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ------------------------- | ------ | -------- | ------------------------------------------ |
| `product_id` | int | no | single product id |
| `underlying_asset_symbol` | string | no | e.g. `BTC`; returns all positions under it |
Pass **exactly one** of the two. For `unrealized_pnl`, `margin`, `mark_price`,
`liquidation_price` and other analytics, use `get_margined_positions`.
```text
Do I have an open BTC position? Show entry price and size.
```
## get\_margined\_positions [#get_margined_positions]
All open margined positions with analytics. The tool to use for risk and P\&L.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ------------------------------------------------------------ |
| `contract_types` | string\[] | no | subset of `perpetual_futures`, `call_options`, `put_options` |
| `product_ids` | int\[] | no | max 10 product ids |
`size` is signed (positive = long, negative = short). For notional exposure use
`abs(size) * contract_value * index_price`. Use **`index_price`**, not
`mark_price` (an option's mark is its premium). The tool also patches
`unrealized_pnl` for short options client-side, since the upstream API returns
the unsigned premium value.
```text
Across all my open positions, show unrealised PnL, margin used, and approximate
distance to liquidation. Rank by risk.
```
## get\_product\_leverage [#get_product_leverage]
The order leverage configured for a product on your account.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ------------ | ---- | -------- | -------------------------------- |
| `product_id` | int | yes | product id to fetch leverage for |
```text
What leverage am I set to on BTCUSD?
```
## get\_wallet\_balances [#get_wallet_balances]
Balances across all assets.
**Auth:** Read Data key
No parameters.
Fields: `asset_symbol`, `balance`, `available_balance`, `position_margin`,
`strategy_blocked_amount`. `strategy_blocked_amount` is collateral reserved by an
active Algo Marketplace strategy; normal, not an anomaly.
```text
Show my wallet balances and how much is available vs locked in margin.
```
## get\_wallet\_transactions [#get_wallet_transactions]
Wallet transaction history. Paginated. Timestamps are **microseconds**. Without
`start_time_us`, only the last \~90 days are returned (the response carries a
`notice` field); pass it to reach older history.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ------------------- | --------- | -------- | ------------------------------------------------------------------- |
| `transaction_types` | string\[] | no | e.g. `deposit`, `withdrawal`, `funding`, `settlement`, `commission` |
| `asset_ids` | int\[] | no | filter by asset |
| `start_time_us` | int | no | microseconds epoch |
| `end_time_us` | int | no | microseconds epoch |
| `page_size` | int | no | default 50, max 200 |
| `after` / `before` | string | no | pagination cursors |
```text
Group my wallet transactions for the last 30 days by type and show net change
per asset.
```
## get\_fills [#get_fills]
Your executed trades (fills). Paginated. Timestamps are **microseconds**. Without
`start_time_us`, only the last \~90 days are returned; pass it to reach older
fills.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ----------------------- |
| `product_ids` | int\[] | no | filter by product |
| `contract_types` | string\[] | no | filter by contract type |
| `start_time_us` | int | no | microseconds epoch |
| `end_time_us` | int | no | microseconds epoch |
| `page_size` | int | no | default 50, max 200 |
| `after` | string | no | pagination cursor |
```text
List my fills for the last 7 days grouped by symbol with realised PnL.
```
## bulk\_fills\_export [#bulk_fills_export]
Bulk-export your full fills history to a CSV file on disk: for tax, accounting,
or backtesting without dozens of paginated calls.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | -------------------------------------------------------------------------------- |
| `output_path` | string | yes | must be inside the current working directory or your home directory; `~` expands |
| `product_ids` | int\[] | no | filter by product |
| `contract_types` | string\[] | no | filter by contract type |
| `start_time_us` | int | no | microseconds epoch |
| `end_time_us` | int | no | microseconds epoch |
Returns `{path, row_count, size_bytes}`. Without `start_time_us`, the export
covers only the last \~90 days; for a full tax-year export, pass an explicit start
(and usually end) time.
```text
Export all my fills from 1 Jan 2026 to today to ~/delta-fills-2026.csv.
```
## get\_order\_history [#get_order_history]
Closed / cancelled orders, filterable and paginated. Timestamps are
**microseconds**.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ---------------------------------------------------------- |
| `product_ids` | int\[] | no | filter by product |
| `contract_types` | string\[] | no | filter by contract type |
| `order_types` | string\[] | no | `market`, `limit`, `stop_market`, `stop_limit`, `all_stop` |
| `start_time_us` | int | no | microseconds epoch |
| `end_time_us` | int | no | microseconds epoch |
| `page_size` | int | no | default 50, max 200 |
| `after` | string | no | pagination cursor |
```text
Show my cancelled and filled orders on ETHUSD over the last week.
```
## get\_open\_orders [#get_open_orders]
Current open / pending orders. Paginated.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | --------------------------- |
| `states` | string\[] | no | subset of `open`, `pending` |
| `product_ids` | int\[] | no | max 10 product ids |
| `contract_types` | string\[] | no | filter by contract type |
| `page_size` | int | no | default 50, max 200 |
| `after` | string | no | pagination cursor |
```text
What open orders do I have right now, and at what prices?
```
## get\_order\_by\_id [#get_order_by_id]
Fetch a single order by id or client order id.
**Auth:** Read Data key
| Param | Type | Required | Notes |
| ----------------- | ------ | -------- | ---------------------------- |
| `order_id` | int | no | Delta-assigned order id |
| `client_order_id` | string | no | your client order id, if set |
Provide **exactly one**.
```text
Look up order 123456789 and show its status and fills.
```
## get\_trading\_preferences [#get_trading_preferences]
Your trading preferences: margin mode, notifications, and similar settings.
**Auth:** Read Data key
No parameters.
```text
What's my current margin mode and trading preferences?
```
## get\_trading\_stats [#get_trading_stats]
Account-level trading volume and statistics.
**Auth:** Read Data key
No parameters.
```text
Show my trading volume and stats for this account.
```
# Trading (/docs/tools/trading)
These tools **place and change real orders and positions**. They register
whenever credentials are present, alongside the account tools. Whether a call
executes is decided by your key: Delta accepts what a **Trading** key sends and
rejects what a **Read Data** key sends (see
[Authentication](/docs/authentication)).
There is no rehearsal step. A call with a Trading key goes to Delta as sent, with
no size cap and no confirmation prompt, sized in contracts rather than coins.
Prices are sent exactly as typed, and Delta moves an off-tick price onto the
product's tick. Mutations are **never** auto-retried, because re-sending an order
can place it twice. Rehearse on `india_testnet`.
## What the server still checks [#what-the-server-still-checks]
Three request-shape checks remain, and they fail before anything is sent:
* Exactly one of `product_id` / `product_symbol` on every tool that names a
product.
* Exactly one of `id` / `client_order_id` on `cancel_order`.
* At least one leg on `place_bracket_order`.
Everything else is Delta's answer, returned as given.
## place\_order [#place_order]
Place a single limit, market, or stop order. Supports attached brackets.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| --------------------------------- | ------ | -------- | ----------------------------------------------------- |
| `size` | int | yes | order size in contracts (positive) |
| `side` | string | yes | `buy` or `sell` |
| `order_type` | string | yes | `limit_order` or `market_order` |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
| `limit_price` | string | no | required for `limit_order`; ignored on `market_order` |
| `stop_order_type` | string | no | `stop_loss_order` or `take_profit_order` |
| `stop_price` | string | no | trigger price for stop orders |
| `trail_amount` | string | no | trailing-stop amount |
| `stop_trigger_method` | string | no | `mark_price`, `last_traded_price`, `spot_price` |
| `time_in_force` | string | no | `gtc` or `ioc` |
| `post_only` | bool | no | reject if it would take liquidity |
| `reduce_only` | bool | no | only reduce an existing position |
| `client_order_id` | string | no | your id, max 32 chars |
| `bracket_stop_loss_price` | string | no | attached-bracket SL trigger |
| `bracket_stop_loss_limit_price` | string | no | attached-bracket SL limit |
| `bracket_take_profit_price` | string | no | attached-bracket TP trigger |
| `bracket_take_profit_limit_price` | string | no | attached-bracket TP limit |
| `bracket_trail_amount` | string | no | attached-bracket trailing amount |
| `bracket_stop_trigger_method` | string | no | trigger method for the bracket |
Passing the `bracket_*` params here creates an **entry-order** bracket whose id
(the returned order id) is what `edit_bracket_order` later expects. (That differs
from `place_bracket_order`, which attaches a bracket to an open position.)
**Prices are sent exactly as given.** Delta moves an off-tick price onto the
product's tick, so the `limit_price` in the response is the one that applies.
```text
Place a GTC limit buy of 5 ETHUSD at 3400 with a take-profit at 3600 and a
stop-loss at 3250.
```
## edit\_order [#edit_order]
Edit an open order's size or price.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ---------------- | ------ | -------- | --------------------------------------------------- |
| `id` | int | yes | order id to edit |
| `size` | int | yes | total size after the edit |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
| `limit_price` | string | no | new limit price |
| `stop_price` | string | no | new stop trigger price |
| `trail_amount` | string | no | new trailing-stop amount |
| `post_only` | bool | no | reject if it would take liquidity |
Prices are sent exactly as given. Delta moves an off-tick price onto the product's
tick, so the `limit_price` in the response is the one that applies.
```text
Move my open BTCUSD order 123456789 to a limit price of 71500.
```
## cancel\_order [#cancel_order]
Cancel a single order by id or client order id.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ----------------- | ------ | -------- | ---------------------------- |
| `product_id` | int | yes | product the order belongs to |
| `id` | int | no | order id to cancel |
| `client_order_id` | string | no | your client order id |
Pass **exactly one** of `id` or `client_order_id`.
```text
Cancel my open BTCUSD order 123456789.
```
## cancel\_all\_orders [#cancel_all_orders]
Cancel open orders, optionally scoped by product or contract type.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ----------------------------------------------------- |
| `product_id` | int | no | limit to one product |
| `contract_types` | string\[] | no | limit to contract types (ignored if `product_id` set) |
Limit orders, stop orders and reduce-only orders are all cancelled. There is no
flag to exclude a kind.
Called bare, this cancels every open order on the account. `product_id` and
`contract_types` are the only way to narrow it.
```text
Cancel all my open orders on BTCUSD.
```
## place\_batch\_orders [#place_batch_orders]
Place several orders on one contract in a single request.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `orders` | object\[] | yes | each `{size, side, order_type, limit_price?, time_in_force?, post_only?, client_order_id?}`. Same contract. No IOC/stop. |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
`client_order_id` must be unique within the batch. Delta's response is returned
as given, and nothing annotates it. When it comes back with fewer orders than you
sent, the missing ones were not accepted: compare the two lists before you resend
anything, because resending a leg that did go live places it twice.
```text
Place a ladder of 5 BTCUSD limit buys: 2 contracts each at 70000, 69500, 69000,
68500, 68000.
```
## edit\_batch\_orders [#edit_batch_orders]
Edit several orders on one contract in a single request.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | ------------------------------------------------------- |
| `orders` | object\[] | yes | each `{id, size, order_type, limit_price?, post_only?}` |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
```text
Reprice all my open ETHUSD ladder orders down by 50.
```
## cancel\_batch\_orders [#cancel_batch_orders]
Cancel several orders on one contract in a single request.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ---------------- | --------- | -------- | --------------------------------------------------- |
| `orders` | object\[] | yes | each `{id}` or `{client_order_id}` |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
```text
Cancel orders 111, 222, and 333 on BTCUSD in one request.
```
## place\_bracket\_order [#place_bracket_order]
Attach a take-profit / stop-loss bracket to an open position. Provide at least
one leg.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ----------------------------- | ------ | -------- | ------------------------------------------------------- |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
| `stop_loss_order` | object | no | `{order_type, stop_price, limit_price?, trail_amount?}` |
| `take_profit_order` | object | no | `{order_type, stop_price, limit_price?}` |
| `bracket_stop_trigger_method` | string | no | `mark_price`, `last_traded_price`, `spot_price` |
These position-bracket legs are **not** editable via `edit_bracket_order` — cancel
and re-place to change them. (`edit_bracket_order` only edits entry-order brackets
created through `place_order`.)
```text
On my open BTCUSD position, attach a stop-loss at 68000 and a take-profit at
75000.
```
## edit\_bracket\_order [#edit_bracket_order]
Edit the bracket (TP/SL) params on an existing **entry order**.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| --------------------------------- | ------ | -------- | --------------------------------------------------- |
| `id` | int | yes | entry-order id whose bracket to update |
| `product_id` | int | no | pass exactly one of `product_id` / `product_symbol` |
| `product_symbol` | string | no | e.g. `BTCUSD` |
| `bracket_stop_loss_price` | string | no | stop-loss trigger price |
| `bracket_stop_loss_limit_price` | string | no | stop-loss limit price |
| `bracket_take_profit_price` | string | no | take-profit trigger price |
| `bracket_take_profit_limit_price` | string | no | take-profit limit price |
| `bracket_trail_amount` | string | no | trailing-stop amount |
| `bracket_stop_trigger_method` | string | no | `mark_price`, `last_traded_price`, `spot_price` |
`id` is the **entry-order** id (an order created with `bracket_*` params via
`place_order`). It does not accept the leg ids of a position bracket from
`place_bracket_order`.
```text
On entry order 123456789, raise the take-profit to 76000.
```
## set\_product\_leverage [#set_product_leverage]
Set order leverage for a product.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ------------ | ------ | -------- | -------------------------------- |
| `product_id` | int | yes | product to set leverage for |
| `leverage` | string | yes | leverage multiplier, e.g. `'10'` |
```text
Set my BTCUSD order leverage to 10x.
```
## adjust\_position\_margin [#adjust_position_margin]
Add or remove isolated margin on a position.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| -------------- | ------ | -------- | ----------------------------------------------------------- |
| `product_id` | int | yes | product id of the position |
| `delta_margin` | string | yes | margin to add (positive) or remove (negative), e.g. `'5.0'` |
```text
Add 5 USDT of isolated margin to my BTCUSD position.
```
## close\_all\_positions [#close_all_positions]
Close every open position on the account, both cross / portfolio-margined and
isolated.
**Auth:** API key; a Trading key to execute
No parameters.
There is no narrower call. Both margin scopes are closed, and there is no flag
that limits it to a product or a scope. The server looks up your `user_id`
itself. To close less than everything, cancel and close by product instead.
```text
Close every open position on my account.
```
## configure\_auto\_topup [#configure_auto_topup]
Override auto top-up for a single position.
**Auth:** API key; a Trading key to execute
| Param | Type | Required | Notes |
| ------------ | ---- | -------- | ----------------------------------------------- |
| `product_id` | int | yes | product id of the position |
| `auto_topup` | bool | yes | enable or disable auto top-up for this position |
```text
Turn on auto top-up for my BTCUSD position.
```
# Setup (/docs/tools/setup)
These register whatever your configuration is, so they are in your client's
tool list before you add anything.
`save_credentials` is the call the form makes when you select **Check and save**.
It is marked app-only, so the assistant does not call it, but your client still
lists it. Claude Desktop shows it under **App-only tools**.
None of them returns your key, your secret, or a fingerprint of either.
## setup\_credentials [#setup_credentials]
Opens a form for your API key and secret, so the values never enter the
conversation. The form asks three things: which site the key came from
(`delta.exchange` or the practice site `demo.delta.exchange`), then the key and
the secret. It checks the key against Delta before saving anything, and writes
`~/.delta-exchange-mcp/config.env`.
**Auth:** No key
This tool takes no parameters. You do not call it by name either. Ask in plain
language and the client picks it:
```text
Connect my Delta Exchange account
```
Rendering a form inline is an optional part of MCP. Claude Desktop and the Codex
desktop app do it today. On any other client nothing appears and the assistant
prints the same instructions instead, which is the intended fallback, not a
failure. See [Authentication](/docs/authentication) for the two ways that work
everywhere.
On a client that shows the form, the running server picks up a saved key at once
and registers the account and trading tools together. Some clients, Claude Desktop
among them, read the tool list only when they start the server, so the new tools
appear after you restart the client. A key that carries Trading permission can
place orders from then on.
## get\_connection\_status [#get_connection_status]
Reports whether a key is configured, which environment it points at, and whether
the account and trading tools are live. Call it when a tool is missing and you
want to know why.
**Auth:** No key
This tool takes no parameters.
```text
What is the Delta MCP connection status?
```
It reconciles safe changes made to the config file outside the running process
before it answers, so a key you added by hand or through
`uvx delta-exchange-mcp login` can be picked up without a restart in some cases.
A value your client sets is read first and wins over the shared file, so a key
saved to the file has no effect while the client passes its own. That case is
worth knowing about if you typed your key into a client config:
[the form saved my key but the assistant still cannot see my
account](/docs/troubleshooting#the-form-saved-my-key-but-the-assistant-still-cannot-see-my-account).
# Agent Context (for LLMs) (/docs/ai-context)
> **For AI agents.** This page is domain context for an LLM using the Delta
> Exchange MCP tools. It explains how Delta's instruments and the tool responses
> are structured so you interpret data correctly. It is not human onboarding;
> for that, start at the [Quickstart](/docs). Read exact, live numbers (prices, fees,
> funding rates, contract specs) from the tools; do not assume them from this
> page. All output is informational, not investment advice. If the trading tools
> are available, see [Trading behavior](#trading-behavior) before placing
> anything.
## Instruments and symbols [#instruments-and-symbols]
Delta Exchange lists these `contract_types`: `perpetual_futures`, `futures`,
`call_options`, `put_options`, `spot`.
* **Perpetual futures**: no expiry; symbol is `UNDERLYING` + quote, e.g.
`BTCUSD`, `ETHUSD`. Tethered to a spot index via funding.
* **Futures**: dated; settle at expiry against the index.
* **Options**: symbol format `{C|P}-{UNDERLYING}-{STRIKE}-{DDMMYY}`. Example:
`C-BTC-66400-010824` = a **Call** on **BTC**, strike **66400**, expiring
**01 Aug 2024**. `P-...` is a put.
* **Spot**: direct asset pairs.
Resolve full metadata for any symbol with `get_product` (tick size, contract
value, settlement asset, leverage caps, state). Discover symbols with
`list_products` / `list_tickers`.
## Expiries (critical date-format gotcha) [#expiries-critical-date-format-gotcha]
Two tools take expiry dates in **different formats**:
| Tool | Field | Format |
| ------------------- | ------------- | ------------ |
| `get_options_chain` | `expiry_date` | `DD-MM-YYYY` |
| `list_products` | `expiry` | `YYYY-MM-DD` |
Mixing these up is a common failure. Delta offers daily, weekly, and monthly
options expiries depending on the underlying.
For expired/settled instruments, use `get_settlement_prices` (or
`list_products(states=["expired"])`). Each product carries `settlement_time`
and `settlement_price`. Use these for post-expiry P\&L reconciliation.
## Contracts and sizing [#contracts-and-sizing]
* **`size` is signed**: positive = long, negative = short.
* Each contract represents `contract_value` units of the underlying (e.g. a BTC
contract may be `0.001` BTC; read it from `get_product`).
* **Notional exposure** (especially for options):
```
notional_usd = abs(size) * contract_value * index_price
```
Use **`index_price`** (spot of the underlying), **not `mark_price`**. For an
option, `mark_price` is the option *premium*, so multiplying by it gives the
premium value, not the underlying exposure. Example: a short BTC call with
`size` 10, `contract_value` 0.001, BTC index 54,270 → notional =
`10 * 0.001 * 54270 = $542.70`, not the \~$7.60 the premium would imply.
## Price types [#price-types]
* **Index price**: composite spot built from multiple exchanges; underlies
futures/options. Inspect composition with `get_indices` (constituent
exchanges, weights, `index_type` ∈ `spot_pair` / `fixed_interest_rate` /
`floating_interest_rate`).
* **Mark price**: fair value used for margin, liquidation, and unrealised P\&L.
For options this equals the option premium.
* **Last price**: last traded price (from `get_ticker`).
## Positions and P\&L [#positions-and-pl]
* `get_positions` returns only `entry_price` and `size` (lightweight).
* `get_margined_positions` returns the analytical fields: `unrealized_pnl`,
`realized_pnl`, `realized_funding`, `margin`, `mark_price`,
`liquidation_price`, `index_price`. Use this for risk and P\&L.
* **Short-option P\&L note:** the upstream API returns the unsigned premium value
for short-option `unrealized_pnl`. The MCP tool patches it client-side as
`(mark_price - entry_price) * size * contract_value` with signed `size`. Long
options and futures pass through unchanged.
## Funding (perpetuals) [#funding-perpetuals]
Funding is a periodic payment exchanged between longs and shorts that tethers a
perpetual's price to its index. As a convention, positive funding means longs
pay shorts; negative means shorts pay longs.
* Current funding rate: `get_ticker`.
* Historical funding (OHLC over the rate): `get_funding_history`.
* Funding you have actually paid/received accrues into `realized_funding` on
`get_margined_positions`.
Read the live rate and Delta's documented funding interval from the data and
official docs; do not assume a fixed number here.
## Fees [#fees]
Delta uses a maker/taker fee model, and options have a separate fee schedule
from futures. Exact rates vary by instrument, tier, and jurisdiction and may be
capped. **Do not fabricate fee numbers.** If a user needs fee figures, direct
them to Delta's official fee schedule, or compute realised costs from their own
`get_fills` records (which reflect actual fees charged) rather than estimating.
## Margin [#margin]
* Margin mode (isolated vs cross) is in `get_trading_preferences`.
* `get_wallet_balances` fields: `asset_symbol`, `balance`, `available_balance`,
`position_margin`, `strategy_blocked_amount`.
* `strategy_blocked_amount` is collateral reserved by an active Algo Marketplace
strategy subscription. It is **normal**; do not flag it as a risk or anomaly.
## Time units (frequent bug source) [#time-units-frequent-bug-source]
| Tool group | Unit |
| ------------------------------------------------------------------- | ---------------- |
| Candle / OHLC / funding / OI / mark-price history (`start`, `end`) | **Unix seconds** |
| Fills, orders, wallet transactions (`start_time_us`, `end_time_us`) | **microseconds** |
Passing the wrong unit in a time filter silently returns empty results.
## Pagination and bulk data [#pagination-and-bulk-data]
* Paginated tools return a `meta.after` cursor; pass it back to fetch the next
page. Caps: `list_products` page\_size ≤ 500; fills/orders/wallet ≤ 200.
* For a user's **full** fills history (tax, accounting, backtests), prefer
`bulk_fills_export` (writes a CSV) over looping `get_fills`.
## Resolutions [#resolutions]
Candle/history tools accept: `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`,
`6h`, `1d`, `1w`.
## Environments [#environments]
`DELTA_MCP_ENV` is `india_prod` (production) or `india_testnet` (testnet). An API
key only works in its matching environment.
## Credentials [#credentials]
A key can come from two places, read in this order: the MCP client's own
configuration first, then `~/.delta-exchange-mcp/config.env`, one file shared by
every MCP client on the machine. **A value the client sets always wins**, and an
empty field in the client means "not answered" and falls through to the file. A
key saved to the file while the client is overriding it has no effect, and
restarting does not change that.
The setup tools are always registered and need no key. `setup_credentials` opens a form
for the key that runs outside the conversation; call it whenever the user wants to
connect an account or replace a key, and never ask for a key or secret in the
conversation instead. It needs a client that renders in-chat forms, and it reports
back when the client cannot. `get_connection_status` reports whether a key is
configured and which environment it points at; it returns no key, secret, or
fingerprint. `save_credentials` is the form's own save call. It is
app-only, so do not call it. `uvx delta-exchange-mcp login`
is the terminal equivalent of the form and works on every client.
## Capability boundary [#capability-boundary]
The server's surface depends on whether a key is present:
* **No key:** the setup tools and the market-data tools.
* **Any valid key:** the account tools and the trading tools, together. There is
**no withdrawal tool in any configuration.**
The tool list does not tell you what the key may do. A Read Data key lists
`place_order` exactly as a Trading key does, and Delta answers it with
`Unauthorized`. Do not
promise the user an order will go through, and do not tell them to enable a mode:
there is none. Report Delta's rejection as what it is, a key-permission problem.
Never fabricate a capability you don't have. If a write tool isn't present, say
so rather than pretending to place an order.
## Trading behavior [#trading-behavior]
Order placement is real and immediate. There is no rehearsal mode and no
confirmation step, so confirm intent with the user before you call a tool that
places, edits, cancels or closes anything.
* **Nothing is checked for you.** No size cap, no notional cap, no rehearsal, no
local record of what was sent. Orders are sized in contracts, not coins.
* **No retries on failure.** Mutations are never auto-retried. If a write times
out or errors, surface it; do **not** re-send, because the first attempt may
have landed.
* **Product reference:** pass exactly one of `product_id` or `product_symbol`.
`limit_order` requires `limit_price`, and `market_order` ignores one. Prices go
to Delta exactly as you give them. Delta moves an off-tick price onto the
product's tick, so the `limit_price` in the response is the one that applies.
* **Order-level flags** (`post_only`, `reduce_only`) are booleans here; the tool
serializes them to Delta's `"true"`/`"false"` string enums for you.
* **Blast-radius tools.** `cancel_all_orders` with no filter cancels every open
order; `close_all_positions` takes no arguments and closes the whole account,
both margin scopes. Neither has a narrower form, so get the user's explicit
instruction first and say plainly what it will affect.
* **Batches** are not capped here; the exchange's own limit still applies.
Delta's response is returned unchanged, and when it carries fewer orders than
were sent, the missing ones were not accepted: compare the lists and report
which, rather than resending the batch.
* **No local log.** Delta's own order and fill history is the record of what
executed. Point the user there.
Frame analysis as research, never advice, and remind the user to verify against
the official Delta Exchange app before acting.
## Install reference [#install-reference]
Canonical config shapes, for agents asked to install the server. The human
walkthrough is the [Quickstart](/docs). `DELTA_API_KEY` / `DELTA_API_SECRET`
are optional; omit both for market data only. A key with Trading permission
places real orders, and needs nothing else set.
Standard `mcpServers` shape — Cursor (`~/.cursor/mcp.json`), Windsurf
(`~/.codeium/windsurf/mcp_config.json`), Claude Desktop
(`claude_desktop_config.json`):
```json
{
"mcpServers": {
"delta-exchange-mcp": {
"command": "uvx",
"args": ["delta-exchange-mcp"],
"env": {
"DELTA_MCP_ENV": "india_prod",
"DELTA_API_KEY": "your-api-key",
"DELTA_API_SECRET": "your-api-secret"
}
}
}
}
```
CLI clients:
```bash
claude mcp add delta-exchange-mcp --scope user --env DELTA_MCP_ENV=india_prod -- uvx delta-exchange-mcp
codex mcp add delta-exchange-mcp --env DELTA_MCP_ENV=india_prod -- uvx delta-exchange-mcp
```
Client quirks: Antigravity (`~/.gemini/config/mcp_config.json`) and Gemini CLI
(`~/.gemini/settings.json`) take the standard `mcpServers` shape above. Zed
(`~/.config/zed/settings.json`) names the top-level key `context_servers` and
nests the launch under `"command": { "path": "uvx", … }`. VS Code
(`.vscode/mcp.json`) names it `servers` and each entry needs
`"type": "stdio"`. OpenClaw (`~/.openclaw/openclaw.json`) nests the entry as
`{ "mcp": { "servers": { … } } }`. Hermes (`~/.hermes/config.yaml`) is YAML
under `mcp_servers`. Codex (`~/.codex/config.toml`) and Grok Build
(`~/.grok/config.toml`) use TOML, table `[mcp_servers.delta-exchange-mcp]`;
Grok Build takes env as the sub-table `[mcp_servers.delta-exchange-mcp.env]`.
On Windows every `~/…` path above is the same file at `%USERPROFILE%\…` with
backslashes, and `.vscode/mcp.json` stays relative to the project. Zed is the
one exception: it reads `%APPDATA%\Zed\settings.json` there, not a translation
of its XDG path. Windows also changes the shell, not the config: PowerShell
reads a trailing `\` as a literal argument, so a multi-line
`claude mcp add` or `codex mcp add` needs a backtick for each line break. The
two commands above are single-line and run unchanged on every platform.
# Security (/docs/security)
The biggest risk with any exchange integration is API-key exposure. This server
is built so that the worst case is small, and so that what the assistant can do
is decided by one thing you control: the permission on the key you give it.
## Your keys never leave your machine [#your-keys-never-leave-your-machine]
The server runs as a **local subprocess** and talks to your AI client over
stdio. It is not a hosted service. Your credentials are read from your local
environment and used only to call Delta's API **directly from your machine**.
Requests are signed locally with HMAC-SHA256. The credentials never pass
through the AI model or any Delta server beyond the normal trading API.
```mermaid
flowchart LR
subgraph local["Your machine"]
direction TB
client["AI client
(Claude Desktop, Cursor, Claude Code)"]
server["delta-exchange-mcp
local subprocess
reads keys from local env"]
end
api["Delta Exchange API
(market + account data)"]
client -- "MCP over stdio
tool calls + results" --> server
server -- "HTTPS, HMAC-signed
bounded by your key permission" --> api
api -- "JSON" --> server
```
The only hop that sees your key is the server-to-Delta call on your own machine
(the right edge above). Nothing sensitive crosses to the AI model.
## Market data needs no key at all [#market-data-needs-no-key-at-all]
With no credentials the server has **no code path to your account**. The
account and trading tools are never registered, and the market-data tools
that remain read public data. If all you want is prices, chains and candles,
give it no key and there is nothing to leak.
## It can never withdraw [#it-can-never-withdraw]
Whatever key it holds, the server has **no withdrawal or transfer tool**. The
trading tools place and manage orders and positions; they cannot move funds off
the exchange. There is no code path to a withdrawal.
## Your key's permission is the only gate [#your-keys-permission-is-the-only-gate]
Save any valid key and both the account tools and the
[trading tools](/docs/tools/trading) register. The server adds no gate of its
own: what happens next is decided on Delta's side.
* A **Read Data** key reads your positions, balances and fills. Delta rejects
every order sent with it, with `Unauthorized`.
* A key carrying **Trading** permission places real orders from the moment it is
saved. There is no mode to set, no restart, and no confirmation step.
That boundary holds because Delta enforces it, not because this server chose to.
Pick the permission you actually want, and give an assistant a Read Data key
unless you want it trading your account.
It does not rehearse an order before sending it, cap notional or position size,
ask you to confirm, keep a local record of what it sent, or convert between
contracts and coins. `close_all_positions` takes no arguments and closes your
entire account. One thing it does do: a mutation is never auto-retried after a
timeout or a rate limit, because re-sending an order can place it twice. Test on
[`india_testnet`](https://demo.delta.exchange) before you use a production key.
## Choose the right key [#choose-the-right-key]
When you create your API key on Delta, grant only what you need: **Read Data**
for data-only use, or **Trading** if you want the assistant to place orders. Add
an IP whitelist so the key works only from your machine (Delta requires one on
Trading keys), and revoke it whenever you want. Revocation is immediate, and it
is how you take trading back. Step-by-step in [Authentication](/docs/authentication).
## Public data needs no key [#public-data-needs-no-key]
The market-data tools (tickers, order book, candles, options chain, OI,
funding, indices, and more) work with **no credentials at all**. You add a key
for the account tools (positions, balances, fills, order history) and the
trading tools, which register together.
[The setup tools](/docs/tools/setup) are always registered and need no key
either. None of them returns your key, your secret, or a fingerprint of either.
## The key never goes through the assistant [#the-key-never-goes-through-the-assistant]
There are two ways to hand over a key, and neither puts it in the conversation.
Your client's own config holds it outside the chat. The in-chat form runs in its
own frame, so what you type there goes straight to
`~/.delta-exchange-mcp/config.env`, a file the server creates owner-only, and the
assistant cannot read it.
Sending the key to the assistant as an ordinary chat message is not the same
thing. A message is in the model's context and is stored in the conversation. If
an assistant offers to take your key that way, decline.
## Match your environment [#match-your-environment]
Use production keys with `DELTA_MCP_ENV=india_prod` and testnet keys with
`india_testnet`. Test on testnet first if you are unsure.
## Open source [#open-source]
The server is MIT-licensed and open. Audit exactly what it does before you run
it. Source: [github.com/delta-exchange/delta-exchange-mcp](https://github.com/delta-exchange/delta-exchange-mcp).
The server connects AI assistants to Delta Exchange for informational and
order-management purposes. It does not provide investment, financial, legal, or
tax advice. Any order it places is on your instruction and your responsibility.
AI output can be inaccurate, incomplete, or non-deterministic.
Always verify against the official Delta Exchange app before acting. Trading
crypto derivatives involves substantial risk of loss. Delta Exchange is
registered with the Financial Intelligence Unit (FIU), Govt. of India.
Availability and features may vary by jurisdiction.
# Troubleshooting (/docs/troubleshooting)
## Why doesn't the server appear in my client? [#why-doesnt-the-server-appear-in-my-client]
* Confirm the config file is the right one for your client and that JSON is
valid (a trailing comma breaks it silently).
* **Fully restart** the client after editing config. Most clients load MCP
servers only at launch.
* Check your client's MCP/developer logs for a startup error from
`delta-exchange-mcp`.
* If you installed the Claude Desktop bundle there is no config file to inspect.
Each extension unpacks into its own directory under
`~/Library/Application Support/Claude/Claude Extensions/`, alongside the
virtualenv built at install time; that directory and the app's own log are
where to look when a bundle installs but won't start.
## `uvx: command not found` [#uvx-command-not-found]
`uv` isn't installed or isn't on your `PATH`. Install it
([instructions](/docs#install-uv)) and restart your terminal **and**
your AI client so it inherits the updated `PATH`. Some GUI clients don't see
shell `PATH` changes until a full restart (or a reboot on macOS).
This applies to the one-click Cursor and VS Code installs too: they write the
entry for you, but the entry still launches the server through `uvx`. The Claude
Desktop bundle is the exception — it fetches its own runtime and never needs
`uv`.
## Why does `uvx delta-exchange-mcp` fail to resolve? [#why-does-uvx-delta-exchange-mcp-fail-to-resolve]
Run it directly in a terminal to see the real error:
```bash
uvx delta-exchange-mcp --help
```
A network/proxy issue or an old `uv` are the usual causes. Update uv:
```bash
uv self update
```
An old server version is another: releases before `0.4.2` do not start on a
fresh install. `uvx` resolves the newest published version on each launch; to
pin one, use `uvx "delta-exchange-mcp==VERSION"`, where `VERSION` is a
release from the [PyPI release history](https://pypi.org/project/delta-exchange-mcp/#history).
## Why does it hang when run in a terminal? [#why-does-it-hang-when-run-in-a-terminal]
Expected: bare `uvx delta-exchange-mcp` starts the MCP server and waits for a
client on stdio. Use `--help` or `--version` for a check that exits.
## Why is the bundle install slow or stuck? [#why-is-the-bundle-install-slow-or-stuck]
The first install of a bundle needs network and can take a while. Claude Desktop
resolves `uv`, downloading it if your machine has none, then fetches a Python
interpreter and the server's dependencies. The app shows this as download
progress. Subsequent installs reuse what it already fetched.
## Why am I getting authentication or signature errors? [#why-am-i-getting-authentication-or-signature-errors]
* The key and `DELTA_MCP_ENV` must match: production key → `india_prod`, testnet
key → `india_testnet`. A mismatch is the most common cause.
* Re-check `DELTA_API_KEY` / `DELTA_API_SECRET` for stray spaces or truncation.
* If you set an IP whitelist on the key, confirm your current IP is allowed.
* Confirm the key still exists and has **Read Data** permission.
## Why do account tools return empty results? [#why-do-account-tools-return-empty-results]
* You may have no open positions/orders. Try a market-data tool first to
confirm the connection works.
* **\~90-day default window:** `get_fills`, `get_wallet_transactions`, and
`bulk_fills_export` return only the last \~90 days unless you pass a
`start_time_us`. If older trades are missing, state an explicit date range in
your prompt.
* Pagination: history tools return a page at a time. Ask the model to follow
`meta.after` cursors for the full set, or use `bulk_fills_export` for fills.
* Timestamps are in **microseconds** for fills/orders/wallet history. A wrong
unit in a time filter silently returns nothing.
## Why do market-data tools work when account tools don't? [#why-do-market-data-tools-work-when-account-tools-dont]
That means the server is running but the key isn't being read. Look for an
account tool such as `get_positions` in your client's tool list: if it is
missing, no credentials reached the server. Verify the `env` block is present
in the config and that you restarted the client. Market data needs no key, so
it works regardless.
The tool list stops there. It tells you whether a key arrived, not what that
key may do, because the account and trading tools register together whatever permission
it carries.
Or ask the assistant to call `get_connection_status`, which answers the same
question directly.
Setting only one of `DELTA_API_KEY` / `DELTA_API_SECRET` has the same effect as
setting neither: both are needed to sign a request, so the account tools stay
unregistered. The server says so on startup — look for a line naming the one
that's missing in your client's MCP logs.
## Why doesn't the key form appear in the chat? [#why-doesnt-the-key-form-appear-in-the-chat]
You asked the assistant to connect your account and it replied with a file path
and a command instead of showing a form.
That is the intended fallback rather than a failure. Rendering a form inline is
an optional part of MCP that only some clients implement, and the server cannot
tell in advance which ones do, so it always returns working instructions
alongside the form. On a client that shows nothing, you see only the
instructions. Claude Desktop and the Codex desktop app render the form today.
Use either of the other two routes, which write the same file the form would
have. Run `uvx delta-exchange-mcp login`, or open
`~/.delta-exchange-mcp/config.env` and fill in the three lines waiting in it.
[Authentication](/docs/authentication) covers both.
## Why can't the assistant see my account after the form saved my key? [#the-form-saved-my-key-but-the-assistant-still-cannot-see-my-account]
The form reports that it saved, and it names a setting your client sets in its
own configuration.
Both statements are true, and together they are the whole failure. A value in
your client's MCP entry, or in the fields it asked you to fill in when you
installed it, is read before the shared file and wins over it. So the form
checked your key against Delta, saved it correctly, and the server carries on
signing with whatever your client passes. Restarting does not help, because the
client passes its own value again at every launch.
This is the one case where the install builder's own convenience works against
you: if you typed your key into the generated config, that key is the one in
force no matter what the form saves afterwards.
Clear those fields from that client's entry and restart it. The message the form
shows names which setting is at fault. `uvx delta-exchange-mcp login` runs the
same check and warns on stderr, though it reports what your **shell** is setting,
because that is the environment it can see.
## Why don't the trading tools appear? [#why-dont-the-trading-tools-appear]
They register with the account tools, whenever `DELTA_API_KEY` and
`DELTA_API_SECRET` both reach the server. If the account tools are missing too,
the key is not being read: see
[the question above](#why-do-market-data-tools-work-when-account-tools-dont).
There is no mode to switch on. A key saved through the in-chat form or the shared
file arms both groups in the running server. Some clients, Claude Desktop among
them, show the new tools only after you restart the client. A key you put in your
client's `env` block arrives only when the client relaunches the server.
## Why does a trading tool return a permission or IP error? [#why-does-a-trading-tool-return-a-permission-or-ip-error]
* The API key must have **Trading** permission enabled in Delta API management.
A Read Data key lists the trading tools and Delta rejects what they send with
`Unauthorized`. Create a
key with the permission you want; there is no setting here that grants it.
* The requesting IP must be **whitelisted** on the key. The error context names
the IP Delta saw, so add that one to the key's whitelist. Delta requires a
whitelist entry on every Trading key.
* After a mutation **signature error**, don't retry blindly: mutations are never
auto-retried because the first attempt may have reached the exchange. Check
`get_open_orders` / `get_positions` before re-sending.
## Why does my order rest at a different price than I asked for? [#why-does-my-order-rest-at-a-different-price-than-i-asked-for]
Prices are sent to Delta exactly as given, and Delta moves a price that is off the
product's tick onto the tick. The `limit_price` in the response is the price that
applies. Read the tick from `get_product` and price to it.
## Where is the record of what the assistant sent? [#where-is-the-record-of-what-the-assistant-sent]
Delta's own order and fill history. The server keeps no local log of orders: use
`get_order_history` and `get_fills`, or the Delta app.
## Why am I hitting rate limits or intermittent failures? [#why-am-i-hitting-rate-limits-or-intermittent-failures]
Delta's API is rate-limited. Rapid-fire prompts across many symbols can trip
limits; space requests out or narrow the query. Transient errors usually clear
on retry.
## I saved my key in Claude Desktop, but account tools are still missing [#i-saved-my-key-in-claude-desktop-but-account-tools-are-still-missing]
Quit Claude Desktop completely (Cmd+Q on macOS), reopen it, and ask for your
positions in a new chat. Turning the extension off and on is not enough.
The saved key is kept; you do not need to enter it again.
The server can register account tools before Claude Desktop refreshes its tool
list. A successful save confirms the key is stored, but does not confirm that
Claude can use the new tools yet. Clients that refresh the list immediately can
continue without restarting.
## How do I update the server? [#how-do-i-update-the-server]
On the `uvx` paths — including the one-click Cursor and VS Code installs — `uvx`
caches the package. To force the latest version:
```bash
uvx --refresh delta-exchange-mcp --help
```
If you installed the Claude Desktop bundle, download the
[latest bundle](https://github.com/delta-exchange/delta-exchange-mcp/releases/latest/download/delta-exchange-mcp.mcpb)
and open it again. Then quit Claude Desktop completely (Cmd+Q on macOS) and
reopen it. Turning the extension off and on does not reload the server.
## How do I capture a debug log? [#capture-a-debug-log]
When a tool returns something unexpected, the server can record exactly what it
sent and received. Add `DELTA_MCP_DEBUG` to the same `env` block as your
credentials — or, in the Claude Desktop bundle, use a hand-written config, since
the install form has no field for it:
```json title="your client's MCP config — env block"
"env": {
"DELTA_MCP_ENV": "india_prod",
"DELTA_MCP_DEBUG": "1"
}
```
Restart the client and repeat the action. Each HTTP call — request URL with its
filter params, response status, and response body — is written to
`~/.delta-exchange-mcp/logs/`. Override the location with `DELTA_MCP_DEBUG_FILE`.
To find the file, just ask: **"where is the debug log?"** Debug mode registers a
`get_debug_status` tool that returns the exact path, and the path is also in the
startup line your client's MCP logs capture. That extra tool is the one thing
debug mode changes about the tool list.
The log never records your API key, secret, or request signatures. It does record
response bodies, which carry your balances, positions, and transactions — so
review it before attaching it to an issue.
## Still stuck? [#still-stuck]
Open an issue on
[github.com/delta-exchange/delta-exchange-mcp](https://github.com/delta-exchange/delta-exchange-mcp/issues)
with your client, OS, and the error from the logs. A debug log from the section
above turns a vague report into a reproducible one.