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