Skip to content

MCP

Model Context Protocol server: exposes gateway tools to LLM clients. Two transports: stdio / HTTP.

Full parameter-level docs for all 60 tools

This page is a tool-list overview. For each tool's complete parameters (v1.4.83/84 aliases + enum dual-accept + deny_unknown_fields + runtime validate) and JSON-RPC invocation examples see API Reference → MCP Tools (new in v1.4.85).

Tool inventory

Quote (qot:read)

Tool Description
futu_ping Ping the gateway, returns RTT
futu_get_quote Real-time quote (auto-subscribes Basic)
futu_get_snapshot Snapshot (52-week high/low, turnover, book)
futu_get_kline Historical candles (day / week / month / 1-60 min)
futu_get_orderbook Level-2 book (auto-subscribes OrderBook)
futu_get_ticker Tick-by-tick trades
futu_get_rt Intraday time series
futu_get_static Static info (name, lot size, list date)
futu_get_broker Broker queue (HK only)
futu_list_plates Plate/sector list
futu_plate_stocks Plate constituents
futu_get_capital_flow v1.4.25+: capital flow time series
futu_get_capital_distribution v1.4.25+: capital distribution (super-large/large/medium/small)
futu_get_market_state v1.4.25+: market state (open/close/lunch break)
futu_get_history_kline v1.4.26+: historical K-line with rehab and max_count
futu_get_owner_plate v1.4.26+: which plates a stock belongs to
futu_get_reference v1.4.26+: related securities (underlying ↔ warrant / future / option)
futu_get_option_chain v1.4.26+: option chain (grouped call/put by expiry)
futu_get_warrant v1.4.29+: warrant list (volume-sorted, optional underlying)
futu_get_ipo_list v1.4.29+: upcoming/recent IPOs by market
futu_get_future_info v1.4.29+: futures contract info (size, last trade date, sessions)
futu_get_user_security_group v1.4.29+: watchlist groups (custom / system)
futu_get_stock_filter v1.4.29+: stock scanner (minimal; advanced filters via REST)
futu_get_trading_days v1.4.30+: trading day list
futu_get_rehab v1.4.30+: rehab factors (long-term K-line alignment / backtest)
futu_get_suspend v1.4.30+: suspension days
futu_get_user_security v1.4.30+: securities in a watchlist group
futu_get_global_state v1.4.30+: gateway global state (market open/close, login, server version)
futu_get_user_info v1.4.30+: user info (per-market quote permissions, subscribe quota)
futu_get_delay_statistics v1.4.30+: delay-statistics summary
futu_get_history_kl_quota v1.4.30+: historical K-line download quota
futu_get_used_quota v1.4.110+: current used subscription and historical K-line quota
futu_get_holding_change v1.4.30+: shareholder changes (executive / institution / fund)
futu_modify_user_security v1.4.30+: modify a watchlist group (add / del / move-out)
futu_get_code_change v1.4.30+: security code changes / temporary tickers (HK for now)
futu_set_price_reminder v1.4.30+: set price reminder
futu_get_price_reminder v1.4.30+: query price reminders
futu_get_option_expiration_date v1.4.30+: option expiry date list
futu_query_subscription v1.4.30+: query current subscriptions
futu_unsubscribe v1.4.30+: unsubscribe market data (supports unsub_all)

Account read (acc:read)

Tool Description
futu_list_accounts Trading account list
futu_get_funds Funds summary
futu_get_positions Positions
futu_get_orders Today's orders
futu_get_deals Today's fills
futu_get_max_trd_qtys v1.4.25+: pre-trade max buy/sell qty
futu_get_order_fee v1.4.25+: fee breakdown per order
futu_get_margin_ratio v1.4.25+: margin ratio
futu_get_history_orders v1.4.25+: historical orders
futu_get_history_deals v1.4.25+: historical fills
futu_sub_acc_push v1.4.30+: subscribe account push (orders / fills)
futu_get_acc_cash_flow v1.4.30+: account cash flow statement (by clearing date)

Trade (trade:real / trade:simulate)

Tool Description Extra args
futu_place_order Place order api_key? per-call override
futu_modify_order Modify / cancel api_key?
futu_cancel_order Cancel (shortcut) api_key?
futu_reconfirm_order Reconfirm pending order api_key?
futu_cancel_all_order v1.4.30+: cancel all pending orders (by market or account-wide) api_key?

Unlock trading (trade:unlock, v1.4+)

Tool Description Extra args
futu_unlock_trade Unlock / re-lock real trading unlock: bool (default true); v1.4.31+ optional otp: String (2FA accounts); v1.4.47+ optional security_firm: i32 (1-7 / FutuHK / hk) to scope to one broker; v1.4.47+ optional acc_ids: Vec<u64> to restrict per-account (intersects with security_firm, resolves shadow sub-account blocking)
  • Plaintext password never enters LLM prompt: the server reads it from the OS keychain (preferred) or the FUTU_TRADE_PWD environment variable (fallback).
  • Ops writes the password into the keychain via futucli set-trade-pwd; the LLM only calls the futu_unlock_trade tool — password never flows through the model.
  • MD5 is computed server-side, then sent to the gateway.
  • After unlock, the gateway process caches the cipher until the gateway restarts; individual orders don't need to re-unlock.
  • v1.4.31+ per-broker unlock + fine-grained response: the response carries total_requested / total_unlocked / failed_accounts fields; on partial failure, ok=false explicitly lists which accounts didn't unlock (common causes: the account doesn't have trading permission for that market, or it's a "shadow" sub-account).
  • v1.4.31+ 2FA (dynamic password token) accounts: when the server returns need_otp=true, the LLM should prompt the user for the OTP and call again with the otp field populated.

Startup

export FUTU_MCP_API_KEY="fc_xxxx..."
./futu-mcp \
  --gateway 127.0.0.1:11111 \
  --keys-file ~/.config/futu/keys.json

JSON-RPC frames over stdin/stdout, launched by the LLM client as a child process.

./futu-mcp \
  --gateway 127.0.0.1:11111 \
  --keys-file ~/.config/futu/keys.json \
  --http-listen 127.0.0.1:38765
  • POST /mcp — rmcp streamable HTTP transport
  • GET /metrics — Prometheus (no token required)
  • GET /.well-known/oauth-protected-resource — OAuth 2.0 Protected Resource Metadata (RFC 9728, v1.4+; lets MCP clients auto-discover scope requirements)

OAuth metadata endpoint (v1.4+)

A /mcp request without Authorization: Bearer returns 401 + WWW-Authenticate: Bearer resource_metadata="/.well-known/oauth-protected-resource". The client fetches that URL to learn the required scopes:

{
  "resource": "/mcp",
  "bearer_methods_supported": ["header"],
  "scopes_supported": [
    "qot:read",
    "acc:read",
    "trade:simulate",
    "trade:real",
    "trade:unlock"
  ],
  "resource_name": "FutuOpenD-rs MCP",
  "resource_documentation": "https://futuapi.com/guide/mcp/"
}

Why not a full OAuth server?

Futu API keys are manually-configured long-lived credentials — there's no interactive consent flow. RFC 9728 is designed exactly for "declare the auth requirement, don't perform the flow" resource servers. The actual token (= API key) is still handed out out-of-band by ops and written into the MCP client config's Authorization header.

Per-call API key precedence (v1.1+)

1. `api_key` field in the tool args (explicit)
2. HTTP Authorization: Bearer <token> (HTTP transport only)
3. Startup-time --api-key / FUTU_MCP_API_KEY env var

stdio mode has no HTTP header → falls back 2→3. HTTP mode lets multiple LLMs each carry their own token, with audit / limits tracked independently.

Central scope registry

guard::scope_for_tool(name) -> Option<ToolScope> is the single source of truth. Adding a new #[tool] requires updating this registry — otherwise the handler returns unknown MCP tool and the all_known_tools_have_scopes test breaks.

SIGHUP hot reload

kill -HUP $(pgrep futu-mcp)

Changes to a key's scope / limits / expires_at / revocation take effect immediately on MCP (since v0.8+, MCP looks up KeyStore on every request by key_id).

Trading-tool security boundary

  • unlock_trade takes no password arg (v1.4+) — futu_unlock_trade only has unlock: bool; the server reads the password from the OS keychain / env var. The LLM prompt and tool-call log never see the password.
  • Simulate by defaultPlaceOrderReq.env defaults to "simulate"; the LLM must explicitly pass "real" to hit the real account.
  • Scope isolationtrade:simulate can never place a real order (even if env is spoofed to real, require_trading rejects it).
  • Limits always apply — the handler runs the full CheckCtx: market / symbol / value / side / daily checks.
  • WS push defense in depth (v1.4+) — even if the subscription gate slips, push dispatch runs another scope filter; filtered pushes increment futu_ws_push_filtered_total.

MCP client integration

See Tutorial: MCP integration for Claude Desktop / Cursor / Continue configuration examples.