# Candor FX > Candor FX connects your MT5 account to your AI assistant. Ask about your balance, positions and prices in any chat. Read only. Candor FX is a read-only MCP server for MetaTrader 5 accounts. It cannot place, change or cancel trades. It gives no financial advice. - MCP address (Streamable HTTP, OAuth sign-in with an email code): each company or IB gives its people their own address in the invitation. - Privacy: https://www.sovirex.com/privacy - Terms: https://www.sovirex.com/terms ## Setup The person signs in on the connector's sign-in window, then saves their MT5 broker, server, account number and password on https://www.sovirex.com/. The password is only ever typed on that page, never in chat. ## Tools ### accounts The MT5 accounts saved for you: id, optional displayName, broker, server, login and passwordKind (investor or master, once a login has shown which). Use displayName to match a trader’s account name, then pass its id as `account`; if names repeat, ask which account they mean. Not needed before other calls: they work without `account` when one account is saved, and list the accounts when several are. With none saved, the answer has `next` with the page that adds one. Arguments: none. ### all_accounts For each MT5 account saved for you: balance, equity, margin_level, currency, open_positions (count) and floating_profit (sum of the open positions' profit), or an `error` for an account that could not be read. One account failing does not fail the call. Reads each account's terminal, so it can take a minute when terminals start. Facts, not advice. Arguments: none. ### account Balance, equity, margin and details of the linked MT5 account, with margin_level, free_margin and currency as named fields. `mode` is demo, contest or real. Arguments: account (text, optional: an id from `accounts`). ### positions Open positions on the linked MT5 account, or those of one `symbol`. Each has side (buy or sell), opened and opened_at, opened_by (manual, mobile, web, expert, stop_loss, take_profit or stop_out), stop_loss and take_profit (null when not set), profit, swap and net (profit + swap), and `currency` for the money. `total` is how many there are; when more than 200, the first 200 are shown and `capped` says how to narrow it. Times come as readable text in UTC (`opened`: "Fri 7 Aug 2026, 09:35 UTC") and as exact ISO 8601 (`opened_at`: "2026-08-07T09:35:44Z"); if the server clock could not be converted, `time_note` says so. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, optional). ### orders Pending orders on the linked MT5 account, or those of one `symbol`. Each has type (buy_limit, sell_limit, buy_stop, sell_stop, buy_stop_limit or sell_stop_limit), state (placed, filled, partly_filled, cancelled, rejected or expired), placed and placed_at, expires and expires_at, stop_loss and take_profit (null when not set), and `currency`. `total` is how many there are; when more than 200, the first 200 are shown and `capped` says how to narrow it. Times come as readable text in UTC (`opened`: "Fri 7 Aug 2026, 09:35 UTC") and as exact ISO 8601 (`opened_at`: "2026-08-07T09:35:44Z"); if the server clock could not be converted, `time_note` says so. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, optional). ### symbols Names of every symbol the broker offers, or with `query` the names whose name or description contains it (any case), at most 50 (500 without `query`), with `matches` (and `total`) the number found; `capped` says how to narrow it when some were left out. Arguments: account (text, optional: an id from `accounts`); query (text, up to 64 characters, optional). ### spec Contract details of one symbol. Its currencies are currency_base, currency_profit and currency_margin; its quote time, start and expiration come as time, start and expiration (readable) with time_at, start_at and expiration_at (exact), null when not set; Every code is a word, "unknown (n)" for one we do not know: trade_mode (disabled, long only and so on), trade_calc_mode (how margin and profit are calculated: forex, futures, cfd, cfd_index, cfd_leverage, forex_no_leverage, exchange_stocks, exchange_futures and so on), trade_exemode (request, instant, market or exchange), swap_mode (disabled, points, currency_symbol, currency_margin, currency_deposit, interest_current, interest_open, reopen_current or reopen_bid), chart_mode (bid or last), option_mode (european or american), option_right (call or put), order_gtc_mode (gtc, daily or daily_no_stops). Three list what is allowed, separated by commas, or none: filling_mode (fill_or_kill, immediate_or_cancel, book_or_cancel), expiration_mode (gtc, day, specified, specified_day) and order_mode (market, limit, stop, stop_limit, stop_loss, take_profit, close_by). Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required). ### quote Latest bid and ask of one `symbol`, or of 1 to 20 `symbols` in one call (give one of the two). With `symbols` the answer has a row per symbol, in the order asked: its tick, or error "unknown symbol". Each tick has time and time_at. An unknown `symbol` fails with unknown_symbol and `next` says to search `symbols`. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, optional); symbols (list of 1 to 20 names, optional). ### candles Candles of one symbol, oldest first. tf is M1, M5, M15, M30, H1, H4, D1, W1 or MN1. Give `count` (1 to 1000, default 500) for the latest candles, or `from` and `to` (dates, YYYY-MM-DD, `to` included, UTC; at most 366 days) for a range, not both. A range returns at most the first 1000 candles, with `truncated` true when there were more. Each candle has time (readable, UTC) and time_at (exact). Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required); tf (one of M1, M5, M15, M30, H1, H4, D1, W1, MN1, required); count (integer 1 to 1000, optional); from (date, YYYY-MM-DD, optional); to (date, YYYY-MM-DD, optional). ### history Deals from `from` to `to` (dates, YYYY-MM-DD, UTC days; at most 366 days) or the last `days` days (1 to 365; with no range, the last 30 days), or only those of one `symbol`, oldest first, `limit` (up to 500) from `offset`. Each has time and time_at, symbol, type (buy, sell, balance, credit, charge, correction, bonus, commission, interest, dividend, buy_cancelled, sell_cancelled or tax; "unknown (n)" for any other), volume, price, profit, commission and swap, and the answer has `currency`. `total_deals` and `totals` cover every deal in the range (of the `symbol` when given), not only the page: profit, commission, swap, volume (lots of trade deals), deposits, withdrawals (a positive amount) and net (profit + commission + swap). A range that crosses the broker's DST change is converted with one offset, so times on the other side of the change can be an hour off. `all: true` reads every deal since the account opened (pages of `limit`, up to 500, from `offset`); use it for "all", "ever" or "since I opened the account". Arguments: account (text, optional: an id from `accounts`); from (date, YYYY-MM-DD, optional); to (date, YYYY-MM-DD, optional); days (integer 1 to 365, optional); all (true, optional); limit (integer 1 to 500, optional); offset (integer 0 to 100000, optional); symbol (text, up to 64 characters, optional). ### history_orders Closed orders from `from` to `to` (dates, YYYY-MM-DD, UTC days; at most 366 days) or the last `days` days (1 to 365; with no range, the last 30 days), oldest first, `limit` (up to 500) from `offset`. Each has type (buy_limit, sell_limit, buy_stop, sell_stop and so on), state (filled, partly_filled, cancelled, rejected or expired), placed and placed_at, done and done_at, and the answer has `currency`. A range that crosses the broker's DST change is converted with one offset, so times on the other side of the change can be an hour off. `all: true` reads every order since the account opened (pages of `limit`, up to 500, from `offset`); use it for "all", "ever" or "since I opened the account". Arguments: account (text, optional: an id from `accounts`); from (date, YYYY-MM-DD, optional); to (date, YYYY-MM-DD, optional); days (integer 1 to 365, optional); all (true, optional); limit (integer 1 to 500, optional); offset (integer 0 to 100000, optional). ### trades Closed trades that closed from `from` to `to` (dates, YYYY-MM-DD, UTC days; at most 366 days) or in the last `days` days (1 to 365; with no range, the last 30 days), or only those of one `symbol`, oldest close first, `limit` (up to 500) from `offset`; `total_trades` counts all of them. Each trade joins the deals of one position: opened and opened_at, closed and closed_at, open_price and close_price (volume weighted when a position was opened or closed in parts), side of the opening deal, volume (lots opened), profit, commission and swap (summed over its deals) and net (profit + commission + swap), all in `currency`. A position still open, or only partly closed, is not a trade. A range that crosses the broker's DST change is converted with one offset, so times on the other side of the change can be an hour off. Facts, not advice. `all: true` reads every deal since the account opened (pages of `limit`, up to 500, from `offset`); use it for "all", "ever" or "since I opened the account". Arguments: account (text, optional: an id from `accounts`); from (date, YYYY-MM-DD, optional); to (date, YYYY-MM-DD, optional); days (integer 1 to 365, optional); all (true, optional); limit (integer 1 to 500, optional); offset (integer 0 to 100000, optional); symbol (text, up to 64 characters, optional). ### stats Numbers over the closed trades of `trades` (same range rules, `all` too; with no range, the last 30 days, `symbol` optional), each trade by its net: trades (count); wins (net above 0) and losses (net below 0); win_rate (wins as a percent of trades); average_win and average_loss (mean net of each kind, loss negative); profit_factor (total of wins divided by total of losses); expectancy (mean net per trade); max_drawdown (largest fall of the running net total from its highest point, in `currency`) and max_drawdown_percent (that as a percent of starting_balance); net_profit (sum of net); starting_balance (the balance at the start of the range, worked back from today's). A number with nothing to divide by is null; no trades gives zeros and nulls. Facts, not advice. `all: true` counts every trade since the account opened; use it for "all", "ever" or "since I opened the account". Arguments: account (text, optional: an id from `accounts`); from (date, YYYY-MM-DD, optional); to (date, YYYY-MM-DD, optional); days (integer 1 to 365, optional); all (true, optional); symbol (text, up to 64 characters, optional). ### indicator Values of an indicator over the latest candles of one symbol, oldest first, `count` of them (1 to 500, default 100), each with its candle time and time_at and null where the candles do not reach back far enough. `name`: rsi (Wilder smoothing, `period` default 14), sma (simple average of closes, `period` default 20), ema (exponential average of closes, `period` default 20), atr (average true range, Wilder smoothing, `period` default 14) or macd (12, 26 and 9; gives macd, signal and histogram; no `period`). `period` is 1 to 200. Earlier candles are read to warm it up. The newest candle may still be forming. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required); tf (one of M1, M5, M15, M30, H1, H4, D1, W1, MN1, required); name (one of rsi, sma, ema, atr, macd, required); period (integer 1 to 200, optional); count (integer 1 to 500, optional). ### calendar Economic calendar events (Nonfarm Payrolls and the rest) from your broker's MT5 calendar, from `from` to `to` (dates, YYYY-MM-DD, `to` included, UTC; at most 31 days, within 7 days back and 21 days ahead), oldest first. `country` is a country name or a currency code (for example "United States" or "USD"); `importance` is the lowest level wanted: low, medium or high. Each has time (readable, UTC) and time_at (exact, ISO 8601), country, currency, name, importance, actual, forecast and previous, null where there is no number yet. The answer has `count` (shown), `total` (all that match; when more than 200 the first 200 are shown and `capped` says how to narrow it) and `updated` with `updated_at` (when the calendar was last refreshed). Facts, not advice. Arguments: account (text, optional: an id from `accounts`); from (date, YYYY-MM-DD, required); to (date, YYYY-MM-DD, required); country (text, up to 64 characters, optional); importance (one of low, medium, high, optional). ### sessions Trade mode of one symbol (disabled, long only, short only, close only or full) and the time of its last tick (last_tick and last_tick_at). MT5 gives this interface no session hours. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required). ### margin Margin (in `currency`) that MT5 calculates for `volume` lots of `symbol` on one `side` at the current price. Nothing is placed. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required); side (one of buy, sell, required); volume (number 0.001 to 1000, required). ### profit Profit or loss (in `currency`) that MT5 calculates for `volume` lots of `symbol` on one `side` between the `open` and `close` price. Nothing is placed. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required); side (one of buy, sell, required); volume (number 0.001 to 1000, required); open (number 0.00001 to 10000000, required); close (number 0.00001 to 10000000, required). ### ticks The last `count` ticks (1 to 1000, default 100) of one symbol from the last two hours, oldest first. Each has time and time_at. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required); count (integer 1 to 1000, optional). ### book Market depth of one symbol: price, volume and type of each level, where the broker offers it. Facts, not advice. Arguments: account (text, optional: an id from `accounts`); symbol (text, up to 64 characters, required). ### exposure Open volume (long, short and total), position count and floating profit per symbol, summed from the open positions, with `currency`. Facts, not advice. Arguments: account (text, optional: an id from `accounts`). ### add_account A link to a page that adds an MT5 account, with the optional `broker`, `server` and `login` filled in. Takes no password: the trader types it on that page. Nothing is saved by this call. Arguments: broker (text, up to 64 characters, optional); server (text, up to 64 characters, optional); login (text, up to 64 characters, optional). ### remove_account A link to a page that asks the trader to confirm removing the saved MT5 account with this `id` (see `accounts`). Nothing is removed until the trader confirms there. Arguments: id (text, up to 64 characters, required). ### account_link A link to the page for one saved MT5 account (see `accounts`): the page edits its display name, broker, server, login and password, or removes the account. Use it when the trader wants to look at, change or remove one account. Takes no password: the trader types it on that page. Arguments: account_id (text, up to 64 characters, required). ## Limits - 60 calls per person per minute, 600 per minute for all people together. Over the limit the answer is HTTP 429 with retry-after. - Every call is recorded in an audit log (tool, arguments, outcome), never the password or the data returned. ## Errors A failed call returns isError and structuredContent { code, message, next }: next is the call ({ call, args }) or page ({ url }) that fixes it. The text starts with one of these codes. - no_account: No MT5 account saved yet. The person can add one on the account page. - account_unavailable: The saved broker or server left the supported list. Update the existing account with the server name shown in MT5. - account_required: Several accounts are saved; pass `account` with one of the listed ids. - unknown_symbol: The broker has no symbol by that name; call `symbols` with `query` to find the right one. - unknown_account: No saved account has that id. - unavailable: The saved password could not be opened just now, or the activity log could not record the call; ask again in a minute. - bad_request: The MT5 account could not answer, or the request was not readable; check the symbol and the other values, then ask again. - login_refused: The broker did not accept the login. The person can fix the password, broker or server on the account page. - login_failed: The sign-in to MT5 did not finish just now; try again in a minute. - login_locked: Too many refused logins on this account; it is paused for an hour. The person's other accounts keep working. - account_in_use: Another Candor FX sign-in is using this MT5 account right now; try again in a few minutes. - range_too_slow: The range holds more closed trades than can be read in one call; ask again with a shorter range. - busy: Busy; try again in a minute. - timeout: Took too long; try again in a minute. - starting: Your terminal is not ready to answer yet; ask again in a minute. - terminal_error: Something went wrong on our side; try again in a minute. ## Example questions - What open positions do I have on my trading account? - What is my balance and equity right now? - What were the last 20 H1 candles of EURUSD?