Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ version = "0.9.0"
edition = "2024"

[dependencies]
# TODO: switch back to crates.io after the next openapi release
longbridge = { git = "https://github.com/longbridge/openapi.git", branch = "main" }
# TODO: switch back to crates.io after the next openapi release. The branch
# carries the symbol-based (counter-id-free) request contract; move back to
# `main` once it lands there.
longbridge = { git = "https://github.com/longbridge/openapi.git", branch = "feat/remove-counter-id-conversion" }
rust_decimal = "1"
rmcp = { version = "1.4", features = [
"server",
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<a href="https://longbridge.com"><img alt="Longbridge" src="https://img.shields.io/badge/brokerage-Longbridge-ffe000?labelColor=000"></a>
</p>

Official MCP server for the [Longbridge](https://longbridge.com) brokerage. **163 tools** across real-time quotes, options, order routing, fundamentals, analyst ratings, calendars, IPO, price alerts, DCA plans, grid trading, portfolio analytics and community sharelists — covering **US and HK markets**. Built with Rust using [rmcp](https://github.com/anthropics/rmcp) and [axum](https://github.com/tokio-rs/axum).
Official MCP server for the [Longbridge](https://longbridge.com) brokerage. **164 tools** across real-time quotes, options, order routing, fundamentals, analyst ratings, calendars, IPO, price alerts, DCA plans, grid trading, portfolio analytics and community sharelists — covering **US and HK markets**. Built with Rust using [rmcp](https://github.com/anthropics/rmcp) and [axum](https://github.com/tokio-rs/axum).

---

Expand All @@ -38,7 +38,7 @@ Sign in once with your Longbridge account. Every request runs over the same host

## Highlights

- **163 tools, one endpoint** — quotes, options, order routing, fundamentals, analyst research, screeners, IPO, alerts, DCA, grid trading and portfolio analytics across **US and HK markets**.
- **164 tools, one endpoint** — quotes, options, order routing, fundamentals, analyst research, screeners, IPO, alerts, DCA, grid trading and portfolio analytics across **US and HK markets**.
- **Stateless by design** — every request forwards its Bearer token straight to the Longbridge SDK. No sessions, no database, nothing stored server-side.
- **OAuth 2.1, auto-discovered** — RFC 9728 protected-resource and RFC 8414 authorization-server metadata; clients complete the flow with no token to paste.
- **Clean, typed responses** — snake_case fields, RFC 3339 timestamps, human-readable symbols, and typed `outputSchema` descriptors for compatible clients.
Expand Down Expand Up @@ -80,15 +80,15 @@ On first use, the client reads the `WWW-Authenticate` challenge, fetches `/.well

</details>

## The 163 tools
## The 164 tools

Twenty categories spanning market data, trading, research and account management.

| Category | Count | Coverage |
|----------|-------|----------|
| **Quote** | 32 | Real-time and historical quotes, candlesticks, depth, brokers, options, warrants, watchlists, capital flow, market temperature, short positions, option volume |
| **Fundamental** | 33 | Financial statements/reports, business segments, institutional views, industry peers/valuation, dividends, EPS forecasts, valuations & valuation comparison, company info/executives, shareholders, corporate actions, operating metrics |
| **Trade** | 14 | Order submission/cancellation/replacement, positions, balance, executions, cash flow, margin |
| **Trade** | 15 | Order submission/cancellation/replacement, multi-leg option combination orders, positions, balance, executions, cash flow, margin |
| **Market** | 15 | Market status, industry/top-mover rank, broker holdings, A/H premium, trade statistics, anomalies, short trades/margin, index constituents |
| **DCA** | 9 | Dollar-cost averaging plan create/update/pause/resume/stop, execution history, statistics, support check |
| **Grid** | 11 | Grid trading order submit/replace/cancel/suspend/restart, list/detail/trigger-history reads, per-symbol setup info, one-time strategy consent |
Expand Down
1 change: 1 addition & 0 deletions data/scopes.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
"grid_submit",
"grid_suspend",
"replace_order",
"submit_multileg_order",
"submit_order"
]
}
Expand Down
23 changes: 11 additions & 12 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Longbridge MCP Server is a Rust service with no durable session state that expos

2. **Direct OAuth** — The server does not proxy OAuth. It publishes [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) Protected Resource Metadata pointing MCP clients directly to Longbridge's OAuth authorization server.

3. **Streaming JSON transformation** — Responses are transformed (snake_case, timestamp conversion, counter_id mapping) during serialization via a custom `serde::Serializer` wrapper, avoiding intermediate allocations.
3. **Streaming JSON transformation** — Responses are transformed (snake_case, timestamp conversion) during serialization via a custom `serde::Serializer` wrapper, avoiding intermediate allocations.

## Request Lifecycle

Expand Down Expand Up @@ -56,7 +56,6 @@ Longbridge MCP Server is a Rust service with no durable session state that expos
src/
├── main.rs Entry point, CLI/config, server startup
├── error.rs Unified error type (thiserror)
├── counter.rs Symbol ↔ counter_id bidirectional conversion
├── metrics.rs Prometheus metrics and /metrics handler
├── ws_pool.rs Cached QuoteContext pool (idle TTL, capacity eviction)
Expand All @@ -69,14 +68,13 @@ src/
├── serialize/
│ ├── mod.rs Public API: to_tool_json(), transform_json()
│ ├── transform.rs TransformSerializer + compound type wrappers
│ ├── timestamp.rs TimestampSerializer (_at fields → RFC 3339)
│ └── counter_id.rs CounterIdSerializer (counter_id → symbol)
│ └── timestamp.rs TimestampSerializer (_at fields → RFC 3339)
└── tools/
├── mod.rs McpContext, #[tool_router], forwarding layer, TOOL_ENDPOINTS
├── quote.rs Quote tools (32)
├── fundamental.rs Fundamental data tools (31)
├── trade.rs Trade tools (15)
├── trade.rs Trade tools (16)
├── market.rs Market data tools (14)
├── dca.rs Dollar-cost averaging tools (9)
├── sharelist.rs Community sharelist tools (8)
Expand Down Expand Up @@ -156,14 +154,13 @@ This struct is the single point of extension for future per-request context (e.g

## JSON Response Transformation

All tool responses pass through a custom `serde::Serializer` wrapper that performs three transformations in a single serialization pass:
All tool responses pass through a custom `serde::Serializer` wrapper that performs its transformations in a single serialization pass:

| Transformation | Example |
|---------------|---------|
| Field names → snake_case | `lastDone` → `last_done` |
| `*_at` fields (i64) → RFC 3339 | `1700000000` → `2023-11-14T22:13:20Z` |
| `counter_id` → `symbol` | `ST/US/TSLA` → `TSLA.US` |
| `counter_ids` → `symbols` | `["ST/US/TSLA"]` → `["TSLA.US"]` |
| Non-identifier map keys pass through | `{"AAPL.US": {…}}` stays `AAPL.US`, not `a_a_p_l._u_s` |

Two entry points:

Expand Down Expand Up @@ -218,12 +215,14 @@ SDK tools create `QuoteContext`/`TradeContext`/`ContentContext`/`AssetContext`/`

## Symbol Mapping

Longbridge HTTP APIs use an internal `counter_id` format (`ST/US/TSLA`, `ETF/US/SPY`, `IX/HK/HSI`). The MCP server converts between this and the user-facing symbol format (`TSLA.US`, `SPY.US`, `HSI.HK`):
The server does not convert between symbols and Longbridge's internal `counter_id` format (`ST/US/TSLA`, `ETF/US/SPY`, `IX/HK/HSI`) in either direction:

- **Request path**: `symbol_to_counter_id()` converts tool input parameters before HTTP calls
- **Response path**: `TransformSerializer` automatically renames `counter_id` → `symbol` and converts values
- **Request path**: tool input symbols (`TSLA.US`, `SPY.US`, `HSI.HK`) go upstream as the `symbol` (or `symbols`) parameter untouched; the backend resolves them itself. Callers are expected to pass the canonical form — the backend matches HK codes exactly, so a zero-padded `00700.HK` is not the same as `700.HK` and comes back as an empty record.
- **Response path**: wherever the backend still returns a `counter_id`, it returns the matching `symbol` alongside it, so nothing needs rewriting. Renaming `counter_id` → `symbol` would in fact emit the key twice.

ETF detection uses an embedded list of ~4,500 US ETF symbols compiled into the binary at build time.
The one thing the transform still has to know about symbols is that they appear as **map keys** (e.g. `{"symbols": {"AAPL.US": {…}}}`). Those keys are data, not field names, so `serialize::is_field_name()` keeps them out of the snake_case pass.

There is no local instrument-type table either, so nothing distinguishes an ETF from an index or a stock before the call. Where that mattered, the upstream answer decides instead: `constituent` asks for an ETF's asset allocation first and falls back to index constituents when the allocation comes back empty, and `dividend` always uses `company-dividends`, which covers ETFs too.

## Metrics

Expand Down
17 changes: 15 additions & 2 deletions locales/zh-CN/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,19 @@
"remark": "委托备注(最多 255 字符)"
}
},
"submit_multileg_order": {
"title": "提交组合期权委托",
"description": "提交多腿期权组合委托,各腿作为一个策略单一起成交或挂单。strategy:CoveredCall(备兑看涨)/ CoveredPut(备兑看跌)/ VerticalCallSpread(垂直看涨价差)/ VerticalPutSpread(垂直看跌价差)/ Collar(领口)/ Straddle(跨式)/ Strangle(宽跨式);side:Buy/Sell(整个策略的方向);order_type:LO(需 submitted_price,为组合净价)或 MO;legs[]:{symbol, ratio_quantity},按策略顺序排列,仅接受期权代码;ratio_quantity 恒为正数——每条腿的买卖方向由 strategy 与 side 共同决定",
"properties": {
"strategy": "组合策略,决定所需腿数与每条腿的方向:`CoveredCall`(备兑看涨)/ `CoveredPut`(备兑看跌)/ `VerticalCallSpread`(垂直看涨价差)/ `VerticalPutSpread`(垂直看跌价差)/ `Collar`(领口)/ `Straddle`(跨式)/ `Strangle`(宽跨式)",
"side": "买卖方向:`Buy`(买入)或 `Sell`(卖出),指整个策略的方向",
"order_type": "委托类型:`LO`(限价,需 `submitted_price`)或 `MO`(市价)",
"submitted_quantity": "委托组数(每组为一套按 `legs` 比例构成的腿)",
"legs": "组合的各条腿,按策略顺序排列,仅接受期权代码",
"submitted_price": "整个组合的净限价,`LO` 必填",
"remark": "委托备注(最多 255 字符)"
}
},
"ah_premium": {
"title": "A/H 溢价",
"description": "获取 A/H 股溢价历史 K 线数据,返回 items[]{timestamp, open, high, low, close},表示溢价百分比",
Expand Down Expand Up @@ -327,7 +340,7 @@
},
"alert_list": {
"title": "价格预警列表",
"description": "获取所有已配置的价格预警,返回 lists[]{counter_id, indicators[]{id, condition, price, frequency, enabled, triggered_at}}"
"description": "获取所有已配置的价格预警,返回 lists[]{symbol, indicators[]{id, condition, price, frequency, enabled, triggered_at}}"
},
"anomaly": {
"title": "市场异动",
Expand Down Expand Up @@ -1315,4 +1328,4 @@
}
}
}
}
}
17 changes: 15 additions & 2 deletions locales/zh-HK/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,19 @@
"remark": "委託備註(最多 255 字符)"
}
},
"submit_multileg_order": {
"title": "提交組合期權委託",
"description": "提交多腿期權組合委託,各腿作為一個策略單一起成交或掛單。strategy:CoveredCall(備兌認購)/ CoveredPut(備兌認沽)/ VerticalCallSpread(垂直認購價差)/ VerticalPutSpread(垂直認沽價差)/ Collar(領口)/ Straddle(跨式)/ Strangle(寬跨式);side:Buy/Sell(整個策略的方向);order_type:LO(需 submitted_price,為組合淨價)或 MO;legs[]:{symbol, ratio_quantity},按策略順序排列,僅接受期權代碼;ratio_quantity 恆為正數——每條腿的買賣方向由 strategy 與 side 共同決定",
"properties": {
"strategy": "組合策略,決定所需腿數與每條腿的方向:`CoveredCall`(備兌認購)/ `CoveredPut`(備兌認沽)/ `VerticalCallSpread`(垂直認購價差)/ `VerticalPutSpread`(垂直認沽價差)/ `Collar`(領口)/ `Straddle`(跨式)/ `Strangle`(寬跨式)",
"side": "買賣方向:`Buy`(買入)或 `Sell`(賣出),指整個策略的方向",
"order_type": "委託類型:`LO`(限價,需 `submitted_price`)或 `MO`(市價)",
"submitted_quantity": "委託組數(每組為一套按 `legs` 比例構成的腿)",
"legs": "組合的各條腿,按策略順序排列,僅接受期權代碼",
"submitted_price": "整個組合的淨限價,`LO` 必填",
"remark": "委託備註(最多 255 字符)"
}
},
"ah_premium": {
"title": "A/H 溢價",
"description": "獲取 A/H 股溢價歷史 K 線數據,返回 items[]{timestamp, open, high, low, close},表示溢價百分比",
Expand Down Expand Up @@ -327,7 +340,7 @@
},
"alert_list": {
"title": "價格預警列表",
"description": "獲取所有已配置的價格預警,返回 lists[]{counter_id, indicators[]{id, condition, price, frequency, enabled, triggered_at}}"
"description": "獲取所有已配置的價格預警,返回 lists[]{symbol, indicators[]{id, condition, price, frequency, enabled, triggered_at}}"
},
"anomaly": {
"title": "市場異動",
Expand Down Expand Up @@ -1315,4 +1328,4 @@
}
}
}
}
}
10 changes: 5 additions & 5 deletions server.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "com.longbridge/mcp",
"description": "US/HK markets — 163 tools: quotes, options, orders, fundamentals, screener, IPO, alerts, DCA & grid",
"description": "US/HK markets — 164 tools: quotes, options, orders, fundamentals, screener, IPO, alerts, DCA & grid",
"version": "0.9.0",
"repository": {
"url": "https://github.com/longbridge/longbridge-mcp",
Expand Down Expand Up @@ -92,9 +92,9 @@
}
},
"localizedDescriptions": {
"en": "Longbridge — official MCP server for the Longbridge brokerage. 163 tools across real-time quotes, options, order routing, fundamentals, stock screener, shareholders, short selling, IPO, calendars, alerts, DCA, grid trading and portfolio analytics for US / HK markets.",
"zh-CN": "长桥证券官方 MCP 服务:163 个工具覆盖美股 / 港股的实时行情、期权、下单路由、基本面、选股器、股东持仓、卖空数据、IPO 打新、财报日历、价格预警、定投计划、网格交易与组合分析。",
"zh-HK": "長橋證券官方 MCP 伺服器:163 個工具覆蓋美股 / 港股的即時行情、期權、下單路由、基本面、選股器、股東持倉、賣空數據、IPO 打新、財報日曆、價格警示、定投計劃、網格交易與組合分析。"
"en": "Longbridge — official MCP server for the Longbridge brokerage. 164 tools across real-time quotes, options, order routing, fundamentals, stock screener, shareholders, short selling, IPO, calendars, alerts, DCA, grid trading and portfolio analytics for US / HK markets.",
"zh-CN": "长桥证券官方 MCP 服务:164 个工具覆盖美股 / 港股的实时行情、期权、下单路由、基本面、选股器、股东持仓、卖空数据、IPO 打新、财报日历、价格预警、定投计划、网格交易与组合分析。",
"zh-HK": "長橋證券官方 MCP 伺服器:164 個工具覆蓋美股 / 港股的即時行情、期權、下單路由、基本面、選股器、股東持倉、賣空數據、IPO 打新、財報日曆、價格警示、定投計劃、網格交易與組合分析。"
},
"icons": [
{
Expand Down Expand Up @@ -138,7 +138,7 @@
"name": "Hong Kong"
}
],
"toolCount": 163,
"toolCount": 164,
"toolCategories": {
"quote": 32,
"fundamental": 33,
Expand Down
8 changes: 0 additions & 8 deletions src/counter.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
mod auth;
mod counter;
mod error;
mod logging;
mod metrics;
Expand Down
Loading
Loading