Skip to main content

futu_mcp/tools/
market.rs

1//! MCP core market-data tools (quote, snapshot, K-line, ticker, RT, static, broker, plates).
2
3use crate::handlers;
4use crate::tool_args::{
5    KLineReq, OrderBookReq, PlateListReq, PlateStocksReq, SymbolListReq, SymbolReq, TickerReq,
6};
7use rmcp::{RoleServer, handler::server::wrapper::Parameters, service::RequestContext};
8
9use super::FutuServer;
10
11impl FutuServer {
12    async fn futu_get_quote_impl(
13        &self,
14        Parameters(req): Parameters<SymbolReq>,
15        req_ctx: RequestContext<RoleServer>,
16    ) -> std::result::Result<String, String> {
17        tracing::info!(tool = "futu_get_quote", symbol = %req.symbol);
18        let client = self
19            .read_client_or_err("futu_get_quote", &req_ctx, None, None)
20            .await?;
21        Self::wrap_result(handlers::core::get_quote(&client, &req.symbol).await)
22    }
23
24    async fn futu_get_snapshot_impl(
25        &self,
26        Parameters(req): Parameters<SymbolReq>,
27        req_ctx: RequestContext<RoleServer>,
28    ) -> std::result::Result<String, String> {
29        tracing::info!(tool = "futu_get_snapshot", symbol = %req.symbol);
30        let client = self
31            .read_client_or_err("futu_get_snapshot", &req_ctx, None, None)
32            .await?;
33        Self::wrap_result(handlers::core::get_snapshot(&client, &req.symbol).await)
34    }
35
36    async fn futu_get_kline_impl(
37        &self,
38        Parameters(req): Parameters<KLineReq>,
39        req_ctx: RequestContext<RoleServer>,
40    ) -> std::result::Result<String, String> {
41        req.validate()?;
42        tracing::info!(
43            tool = "futu_get_kline",
44            symbol = %req.symbol,
45            kl_type = %req.kl_type,
46            // v1.4.90 P2-C: Option<i32> -> f64 NaN sentinel, JSON layer 输出 number / null
47            count = crate::state::audit_fmt::opt_i32(req.count)
48        );
49        let client = self
50            .read_client_or_err("futu_get_kline", &req_ctx, None, None)
51            .await?;
52        Self::wrap_result(
53            handlers::market::get_kline(
54                &client,
55                &req.symbol,
56                &req.kl_type,
57                req.count,
58                req.begin.as_deref(),
59                req.end.as_deref(),
60            )
61            .await,
62        )
63    }
64
65    async fn futu_get_orderbook_impl(
66        &self,
67        Parameters(req): Parameters<OrderBookReq>,
68        req_ctx: RequestContext<RoleServer>,
69    ) -> std::result::Result<String, String> {
70        req.validate()?;
71        tracing::info!(
72            tool = "futu_get_orderbook",
73            symbol = %req.symbol,
74            depth = req.depth,
75            odd_lot = req.odd_lot
76        );
77        let client = self
78            .read_client_or_err("futu_get_orderbook", &req_ctx, None, None)
79            .await?;
80        Self::wrap_result(
81            handlers::market::get_orderbook(&client, &req.symbol, req.depth, req.odd_lot).await,
82        )
83    }
84
85    async fn futu_get_ticker_impl(
86        &self,
87        Parameters(req): Parameters<TickerReq>,
88        req_ctx: RequestContext<RoleServer>,
89    ) -> std::result::Result<String, String> {
90        req.validate()?;
91        tracing::info!(tool = "futu_get_ticker", symbol = %req.symbol, count = req.count);
92        let client = self
93            .read_client_or_err("futu_get_ticker", &req_ctx, None, None)
94            .await?;
95        Self::wrap_result(handlers::market::get_ticker(&client, &req.symbol, req.count).await)
96    }
97
98    async fn futu_get_rt_impl(
99        &self,
100        Parameters(req): Parameters<SymbolReq>,
101        req_ctx: RequestContext<RoleServer>,
102    ) -> std::result::Result<String, String> {
103        tracing::info!(tool = "futu_get_rt", symbol = %req.symbol);
104        let client = self
105            .read_client_or_err("futu_get_rt", &req_ctx, None, None)
106            .await?;
107        Self::wrap_result(handlers::market::get_rt(&client, &req.symbol).await)
108    }
109
110    async fn futu_get_static_impl(
111        &self,
112        Parameters(req): Parameters<SymbolListReq>,
113        req_ctx: RequestContext<RoleServer>,
114    ) -> std::result::Result<String, String> {
115        tracing::info!(tool = "futu_get_static", symbols = ?req.symbols);
116        let client = self
117            .read_client_or_err("futu_get_static", &req_ctx, None, None)
118            .await?;
119        Self::wrap_result(handlers::market::get_static(&client, &req.symbols).await)
120    }
121
122    async fn futu_get_broker_impl(
123        &self,
124        Parameters(req): Parameters<SymbolReq>,
125        req_ctx: RequestContext<RoleServer>,
126    ) -> std::result::Result<String, String> {
127        tracing::info!(tool = "futu_get_broker", symbol = %req.symbol);
128        let client = self
129            .read_client_or_err("futu_get_broker", &req_ctx, None, None)
130            .await?;
131        Self::wrap_result(handlers::market::get_broker(&client, &req.symbol).await)
132    }
133
134    async fn futu_list_plates_impl(
135        &self,
136        Parameters(req): Parameters<PlateListReq>,
137        req_ctx: RequestContext<RoleServer>,
138    ) -> std::result::Result<String, String> {
139        tracing::info!(tool = "futu_list_plates", market = %req.market, set = %req.plate_set);
140        let client = self
141            .read_client_or_err("futu_list_plates", &req_ctx, None, None)
142            .await?;
143        Self::wrap_result(handlers::plate::list_plates(&client, &req.market, &req.plate_set).await)
144    }
145
146    async fn futu_plate_stocks_impl(
147        &self,
148        Parameters(req): Parameters<PlateStocksReq>,
149        req_ctx: RequestContext<RoleServer>,
150    ) -> std::result::Result<String, String> {
151        tracing::info!(tool = "futu_plate_stocks", plate = %req.plate);
152        let client = self
153            .read_client_or_err("futu_plate_stocks", &req_ctx, None, None)
154            .await?;
155        Self::wrap_result(handlers::plate::plate_stocks(&client, &req.plate).await)
156    }
157}
158
159include!(concat!(env!("OUT_DIR"), "/generated_mcp_routes_market.rs"));