Skip to main content

futu_mcp/tools/
reference_f10.rs

1//! MCP F10, financials, research, and valuation reference tools.
2
3use crate::handlers;
4use crate::tool_args::*;
5use rmcp::{
6    RoleServer, handler::server::wrapper::Parameters, service::RequestContext, tool, tool_router,
7};
8
9use super::FutuServer;
10
11#[tool_router(router = reference_f10_tool_router, vis = "pub(crate)")]
12impl FutuServer {
13    #[tool(
14        description = "Company operational efficiency metrics such as employees and per-capita income/profit. Futu API v10.6: OpenQuoteContext.get_company_operational_efficiency."
15    )]
16    async fn futu_get_company_operational_efficiency(
17        &self,
18        Parameters(req): Parameters<CompanyOperationalEfficiencyReq>,
19        req_ctx: RequestContext<RoleServer>,
20    ) -> std::result::Result<String, String> {
21        req.validate()?;
22        tracing::info!(
23            tool = "futu_get_company_operational_efficiency",
24            symbol = %req.symbol,
25            next_key = %crate::state::audit_fmt::opt_str(req.next_key.as_deref()),
26            num = ?req.num,
27            currency_code = %crate::state::audit_fmt::opt_str(req.currency_code.as_deref()),
28            financial_type = ?req.financial_type
29        );
30        let client = self
31            .read_client_or_err(
32                "futu_get_company_operational_efficiency",
33                &req_ctx,
34                None,
35                None,
36            )
37            .await?;
38        Self::wrap_result(
39            handlers::reference::get_company_operational_efficiency(
40                &client,
41                &req.symbol,
42                req.next_key.as_deref(),
43                req.num,
44                req.currency_code.as_deref(),
45                req.financial_type,
46            )
47            .await,
48        )
49    }
50
51    #[tool(
52        description = "Price move around financial earnings announcement dates. Futu API v10.6: OpenQuoteContext.get_financials_earnings_price_move."
53    )]
54    async fn futu_get_financials_earnings_price_move(
55        &self,
56        Parameters(req): Parameters<FinancialsEarningsPriceMoveReq>,
57        req_ctx: RequestContext<RoleServer>,
58    ) -> std::result::Result<String, String> {
59        req.validate()?;
60        tracing::info!(
61            tool = "futu_get_financials_earnings_price_move",
62            symbol = %req.symbol,
63            period_count = ?req.period_count
64        );
65        let client = self
66            .read_client_or_err(
67                "futu_get_financials_earnings_price_move",
68                &req_ctx,
69                None,
70                None,
71            )
72            .await?;
73        Self::wrap_result(
74            handlers::reference::get_financials_earnings_price_move(
75                &client,
76                &req.symbol,
77                req.period_count,
78            )
79            .await,
80        )
81    }
82
83    #[tool(
84        description = "Price history around financial earnings announcement dates. Futu API v10.6: OpenQuoteContext.get_financials_earnings_price_history."
85    )]
86    async fn futu_get_financials_earnings_price_history(
87        &self,
88        Parameters(req): Parameters<FinancialsEarningsPriceHistoryReq>,
89        req_ctx: RequestContext<RoleServer>,
90    ) -> std::result::Result<String, String> {
91        tracing::info!(
92            tool = "futu_get_financials_earnings_price_history",
93            symbol = %req.symbol
94        );
95        let client = self
96            .read_client_or_err(
97                "futu_get_financials_earnings_price_history",
98                &req_ctx,
99                None,
100                None,
101            )
102            .await?;
103        Self::wrap_result(
104            handlers::reference::get_financials_earnings_price_history(&client, &req.symbol).await,
105        )
106    }
107
108    #[tool(
109        description = "Financial statements. Futu API v10.6: OpenQuoteContext.get_financials_statements."
110    )]
111    async fn futu_get_financials_statements(
112        &self,
113        Parameters(req): Parameters<FinancialsStatementsReq>,
114        req_ctx: RequestContext<RoleServer>,
115    ) -> std::result::Result<String, String> {
116        req.validate()?;
117        tracing::info!(
118            tool = "futu_get_financials_statements",
119            symbol = %req.symbol,
120            statement_type = ?req.statement_type,
121            financial_type = ?req.financial_type,
122            currency_code = ?req.currency_code,
123            next_key = ?req.next_key,
124            num = ?req.num
125        );
126        let client = self
127            .read_client_or_err("futu_get_financials_statements", &req_ctx, None, None)
128            .await?;
129        Self::wrap_result(
130            handlers::reference::get_financials_statements(
131                &client,
132                &req.symbol,
133                req.statement_type,
134                req.financial_type,
135                req.currency_code.as_deref(),
136                req.next_key.as_deref(),
137                req.num,
138            )
139            .await,
140        )
141    }
142
143    #[tool(
144        description = "Financials revenue breakdown. Futu API v10.6: OpenQuoteContext.get_financials_revenue_breakdown."
145    )]
146    async fn futu_get_financials_revenue_breakdown(
147        &self,
148        Parameters(req): Parameters<FinancialsRevenueBreakdownReq>,
149        req_ctx: RequestContext<RoleServer>,
150    ) -> std::result::Result<String, String> {
151        req.validate()?;
152        tracing::info!(
153            tool = "futu_get_financials_revenue_breakdown",
154            symbol = %req.symbol,
155            date = ?req.date,
156            financial_type = ?req.financial_type,
157            currency_code = ?req.currency_code
158        );
159        let client = self
160            .read_client_or_err(
161                "futu_get_financials_revenue_breakdown",
162                &req_ctx,
163                None,
164                None,
165            )
166            .await?;
167        Self::wrap_result(
168            handlers::reference::get_financials_revenue_breakdown(
169                &client,
170                &req.symbol,
171                req.date,
172                req.financial_type,
173                req.currency_code.as_deref(),
174            )
175            .await,
176        )
177    }
178
179    #[tool(
180        description = "Research analyst consensus. Futu API v10.6: OpenQuoteContext.get_research_analyst_consensus."
181    )]
182    async fn futu_get_research_analyst_consensus(
183        &self,
184        Parameters(req): Parameters<ResearchAnalystConsensusReq>,
185        req_ctx: RequestContext<RoleServer>,
186    ) -> std::result::Result<String, String> {
187        tracing::info!(
188            tool = "futu_get_research_analyst_consensus",
189            symbol = %req.symbol
190        );
191        let client = self
192            .read_client_or_err("futu_get_research_analyst_consensus", &req_ctx, None, None)
193            .await?;
194        Self::wrap_result(
195            handlers::reference::get_research_analyst_consensus(&client, &req.symbol).await,
196        )
197    }
198
199    #[tool(
200        description = "Research rating summary/detail list. Futu API v10.6: OpenQuoteContext.get_research_rating_summary."
201    )]
202    async fn futu_get_research_rating_summary(
203        &self,
204        Parameters(req): Parameters<ResearchRatingSummaryReq>,
205        req_ctx: RequestContext<RoleServer>,
206    ) -> std::result::Result<String, String> {
207        req.validate()?;
208        tracing::info!(
209            tool = "futu_get_research_rating_summary",
210            symbol = %req.symbol,
211            rating_dimension_type = ?req.rating_dimension_type,
212            uid = ?req.uid,
213            next_key = ?req.next_key,
214            num = ?req.num
215        );
216        let client = self
217            .read_client_or_err("futu_get_research_rating_summary", &req_ctx, None, None)
218            .await?;
219        Self::wrap_result(
220            handlers::reference::get_research_rating_summary(
221                &client,
222                &req.symbol,
223                req.rating_dimension_type,
224                req.uid.as_deref(),
225                req.next_key.as_deref(),
226                req.num,
227            )
228            .await,
229        )
230    }
231
232    #[tool(
233        description = "Morningstar research report. Futu API v10.6: OpenQuoteContext.get_research_morningstar_report."
234    )]
235    async fn futu_get_research_morningstar_report(
236        &self,
237        Parameters(req): Parameters<ResearchMorningstarReportReq>,
238        req_ctx: RequestContext<RoleServer>,
239    ) -> std::result::Result<String, String> {
240        tracing::info!(
241            tool = "futu_get_research_morningstar_report",
242            symbol = %req.symbol
243        );
244        let client = self
245            .read_client_or_err("futu_get_research_morningstar_report", &req_ctx, None, None)
246            .await?;
247        Self::wrap_result(
248            handlers::reference::get_research_morningstar_report(&client, &req.symbol).await,
249        )
250    }
251
252    #[tool(
253        description = "Valuation detail for a stock or index. Futu API v10.6: OpenQuoteContext.get_valuation_detail."
254    )]
255    async fn futu_get_valuation_detail(
256        &self,
257        Parameters(req): Parameters<ValuationDetailReq>,
258        req_ctx: RequestContext<RoleServer>,
259    ) -> std::result::Result<String, String> {
260        req.validate()?;
261        tracing::info!(
262            tool = "futu_get_valuation_detail",
263            symbol = %req.symbol,
264            valuation_type = ?req.valuation_type,
265            interval_type = ?req.interval_type
266        );
267        let client = self
268            .read_client_or_err("futu_get_valuation_detail", &req_ctx, None, None)
269            .await?;
270        Self::wrap_result(
271            handlers::reference::get_valuation_detail(
272                &client,
273                &req.symbol,
274                req.valuation_type,
275                req.interval_type,
276            )
277            .await,
278        )
279    }
280
281    #[tool(
282        description = "Valuation stock list for a plate or index. Futu API v10.6: OpenQuoteContext.get_valuation_plate_stock_list."
283    )]
284    async fn futu_get_valuation_plate_stock_list(
285        &self,
286        Parameters(req): Parameters<ValuationPlateStockListReq>,
287        req_ctx: RequestContext<RoleServer>,
288    ) -> std::result::Result<String, String> {
289        req.validate()?;
290        tracing::info!(
291            tool = "futu_get_valuation_plate_stock_list",
292            symbol = %req.symbol,
293            valuation_type = ?req.valuation_type,
294            next_key = ?req.next_key,
295            num = ?req.num,
296            sort_type = ?req.sort_type,
297            sort_id = ?req.sort_id,
298            filter_security = ?req.filter_security
299        );
300        let client = self
301            .read_client_or_err("futu_get_valuation_plate_stock_list", &req_ctx, None, None)
302            .await?;
303        Self::wrap_result(
304            handlers::reference::get_valuation_plate_stock_list(
305                &client,
306                &req.symbol,
307                req.valuation_type,
308                req.next_key.as_deref(),
309                req.num,
310                req.sort_type,
311                req.sort_id,
312                req.filter_security.as_deref(),
313            )
314            .await,
315        )
316    }
317}