1use std::future::Future;
4use std::sync::Arc;
5
6use futu_net::client::FutuClient;
7use rmcp::{RoleServer, handler::server::wrapper::Parameters, service::RequestContext};
8use serde::de::DeserializeOwned;
9
10use crate::handlers;
11use crate::tool_args::ProtoJsonReq;
12
13use super::FutuServer;
14
15async fn run_qot_proto_json<C2S, F, Fut>(
16 server: &FutuServer,
17 tool_name: &'static str,
18 label: &'static str,
19 req: ProtoJsonReq,
20 req_ctx: RequestContext<RoleServer>,
21 handler: F,
22) -> std::result::Result<String, String>
23where
24 C2S: DeserializeOwned,
25 F: FnOnce(Arc<FutuClient>, C2S) -> Fut,
26 Fut: Future<Output = anyhow::Result<String>>,
27{
28 let c2s = match handlers::proto_json::parse_c2s_json::<C2S>(label, &req.c2s_json) {
29 Ok(c2s) => c2s,
30 Err(err) => return FutuServer::tool_err(err),
31 };
32 let client = server
33 .read_client_or_err(tool_name, &req_ctx, req.api_key.as_deref(), None)
34 .await?;
35 FutuServer::wrap_result(handler(client, c2s).await)
36}
37
38impl FutuServer {
39 async fn futu_get_earnings_calendar_impl(
40 &self,
41 Parameters(req): Parameters<ProtoJsonReq>,
42 req_ctx: RequestContext<RoleServer>,
43 ) -> std::result::Result<String, String> {
44 run_qot_proto_json::<futu_proto::qot_get_earnings_calendar::C2s, _, _>(
45 self,
46 "futu_get_earnings_calendar",
47 "earnings-calendar",
48 req,
49 req_ctx,
50 |client, c2s| async move {
51 handlers::proto_json::earnings_calendar(&client, c2s).await
52 },
53 )
54 .await
55 }
56
57 async fn futu_get_macro_indicator_list_impl(
58 &self,
59 Parameters(req): Parameters<ProtoJsonReq>,
60 req_ctx: RequestContext<RoleServer>,
61 ) -> std::result::Result<String, String> {
62 run_qot_proto_json::<futu_proto::qot_get_macro_indicator_list::C2s, _, _>(
63 self,
64 "futu_get_macro_indicator_list",
65 "macro-indicator-list",
66 req,
67 req_ctx,
68 |client, c2s| async move {
69 handlers::proto_json::macro_indicator_list(&client, c2s).await
70 },
71 )
72 .await
73 }
74
75 async fn futu_get_macro_indicator_history_impl(
76 &self,
77 Parameters(req): Parameters<ProtoJsonReq>,
78 req_ctx: RequestContext<RoleServer>,
79 ) -> std::result::Result<String, String> {
80 run_qot_proto_json::<futu_proto::qot_get_macro_indicator_history::C2s, _, _>(
81 self,
82 "futu_get_macro_indicator_history",
83 "macro-indicator-history",
84 req,
85 req_ctx,
86 |client, c2s| async move {
87 handlers::proto_json::macro_indicator_history(&client, c2s).await
88 },
89 )
90 .await
91 }
92
93 async fn futu_get_fed_watch_target_rate_impl(
94 &self,
95 Parameters(req): Parameters<ProtoJsonReq>,
96 req_ctx: RequestContext<RoleServer>,
97 ) -> std::result::Result<String, String> {
98 run_qot_proto_json::<futu_proto::qot_get_fed_watch_target_rate::C2s, _, _>(
99 self,
100 "futu_get_fed_watch_target_rate",
101 "fed-watch-target-rate",
102 req,
103 req_ctx,
104 |client, c2s| async move {
105 handlers::proto_json::fed_watch_target_rate(&client, c2s).await
106 },
107 )
108 .await
109 }
110
111 async fn futu_get_fed_watch_dot_plot_impl(
112 &self,
113 Parameters(req): Parameters<ProtoJsonReq>,
114 req_ctx: RequestContext<RoleServer>,
115 ) -> std::result::Result<String, String> {
116 run_qot_proto_json::<futu_proto::qot_get_fed_watch_dot_plot::C2s, _, _>(
117 self,
118 "futu_get_fed_watch_dot_plot",
119 "fed-watch-dot-plot",
120 req,
121 req_ctx,
122 |client, c2s| async move {
123 handlers::proto_json::fed_watch_dot_plot(&client, c2s).await
124 },
125 )
126 .await
127 }
128
129 async fn futu_get_earnings_beat_rank_impl(
130 &self,
131 Parameters(req): Parameters<ProtoJsonReq>,
132 req_ctx: RequestContext<RoleServer>,
133 ) -> std::result::Result<String, String> {
134 run_qot_proto_json::<futu_proto::qot_get_earnings_beat_rank::C2s, _, _>(
135 self,
136 "futu_get_earnings_beat_rank",
137 "earnings-beat-rank",
138 req,
139 req_ctx,
140 |client, c2s| async move {
141 handlers::proto_json::earnings_beat_rank(&client, c2s).await
142 },
143 )
144 .await
145 }
146
147 async fn futu_get_dividend_rank_impl(
148 &self,
149 Parameters(req): Parameters<ProtoJsonReq>,
150 req_ctx: RequestContext<RoleServer>,
151 ) -> std::result::Result<String, String> {
152 run_qot_proto_json::<futu_proto::qot_get_dividend_rank::C2s, _, _>(
153 self,
154 "futu_get_dividend_rank",
155 "dividend-rank",
156 req,
157 req_ctx,
158 |client, c2s| async move { handlers::proto_json::dividend_rank(&client, c2s).await },
159 )
160 .await
161 }
162
163 async fn futu_get_dividend_calendar_impl(
164 &self,
165 Parameters(req): Parameters<ProtoJsonReq>,
166 req_ctx: RequestContext<RoleServer>,
167 ) -> std::result::Result<String, String> {
168 run_qot_proto_json::<futu_proto::qot_get_dividend_calendar::C2s, _, _>(
169 self,
170 "futu_get_dividend_calendar",
171 "dividend-calendar",
172 req,
173 req_ctx,
174 |client, c2s| async move {
175 handlers::proto_json::dividend_calendar(&client, c2s).await
176 },
177 )
178 .await
179 }
180
181 async fn futu_get_economic_calendar_impl(
182 &self,
183 Parameters(req): Parameters<ProtoJsonReq>,
184 req_ctx: RequestContext<RoleServer>,
185 ) -> std::result::Result<String, String> {
186 run_qot_proto_json::<futu_proto::qot_get_economic_calendar::C2s, _, _>(
187 self,
188 "futu_get_economic_calendar",
189 "economic-calendar",
190 req,
191 req_ctx,
192 |client, c2s| async move {
193 handlers::proto_json::economic_calendar(&client, c2s).await
194 },
195 )
196 .await
197 }
198
199 async fn futu_get_us_pre_market_rank_impl(
200 &self,
201 Parameters(req): Parameters<ProtoJsonReq>,
202 req_ctx: RequestContext<RoleServer>,
203 ) -> std::result::Result<String, String> {
204 run_qot_proto_json::<futu_proto::qot_get_us_pre_market_rank::C2s, _, _>(
205 self,
206 "futu_get_us_pre_market_rank",
207 "us-pre-market-rank",
208 req,
209 req_ctx,
210 |client, c2s| async move {
211 handlers::proto_json::us_pre_market_rank(&client, c2s).await
212 },
213 )
214 .await
215 }
216
217 async fn futu_get_us_after_hours_rank_impl(
218 &self,
219 Parameters(req): Parameters<ProtoJsonReq>,
220 req_ctx: RequestContext<RoleServer>,
221 ) -> std::result::Result<String, String> {
222 run_qot_proto_json::<futu_proto::qot_get_us_after_hours_rank::C2s, _, _>(
223 self,
224 "futu_get_us_after_hours_rank",
225 "us-after-hours-rank",
226 req,
227 req_ctx,
228 |client, c2s| async move {
229 handlers::proto_json::us_after_hours_rank(&client, c2s).await
230 },
231 )
232 .await
233 }
234
235 async fn futu_get_us_overnight_rank_impl(
236 &self,
237 Parameters(req): Parameters<ProtoJsonReq>,
238 req_ctx: RequestContext<RoleServer>,
239 ) -> std::result::Result<String, String> {
240 run_qot_proto_json::<futu_proto::qot_get_us_overnight_rank::C2s, _, _>(
241 self,
242 "futu_get_us_overnight_rank",
243 "us-overnight-rank",
244 req,
245 req_ctx,
246 |client, c2s| async move {
247 handlers::proto_json::us_overnight_rank(&client, c2s).await
248 },
249 )
250 .await
251 }
252
253 async fn futu_get_top_movers_rank_impl(
254 &self,
255 Parameters(req): Parameters<ProtoJsonReq>,
256 req_ctx: RequestContext<RoleServer>,
257 ) -> std::result::Result<String, String> {
258 run_qot_proto_json::<futu_proto::qot_get_top_movers_rank::C2s, _, _>(
259 self,
260 "futu_get_top_movers_rank",
261 "top-movers-rank",
262 req,
263 req_ctx,
264 |client, c2s| async move { handlers::proto_json::top_movers_rank(&client, c2s).await },
265 )
266 .await
267 }
268
269 async fn futu_get_hot_list_impl(
270 &self,
271 Parameters(req): Parameters<ProtoJsonReq>,
272 req_ctx: RequestContext<RoleServer>,
273 ) -> std::result::Result<String, String> {
274 run_qot_proto_json::<futu_proto::qot_get_hot_list::C2s, _, _>(
275 self,
276 "futu_get_hot_list",
277 "hot-list",
278 req,
279 req_ctx,
280 |client, c2s| async move { handlers::proto_json::hot_list(&client, c2s).await },
281 )
282 .await
283 }
284
285 async fn futu_get_short_selling_rank_impl(
286 &self,
287 Parameters(req): Parameters<ProtoJsonReq>,
288 req_ctx: RequestContext<RoleServer>,
289 ) -> std::result::Result<String, String> {
290 run_qot_proto_json::<futu_proto::qot_get_short_selling_rank::C2s, _, _>(
291 self,
292 "futu_get_short_selling_rank",
293 "short-selling-rank",
294 req,
295 req_ctx,
296 |client, c2s| async move {
297 handlers::proto_json::short_selling_rank(&client, c2s).await
298 },
299 )
300 .await
301 }
302
303 async fn futu_get_period_change_rank_impl(
304 &self,
305 Parameters(req): Parameters<ProtoJsonReq>,
306 req_ctx: RequestContext<RoleServer>,
307 ) -> std::result::Result<String, String> {
308 run_qot_proto_json::<futu_proto::qot_get_period_change_rank::C2s, _, _>(
309 self,
310 "futu_get_period_change_rank",
311 "period-change-rank",
312 req,
313 req_ctx,
314 |client, c2s| async move {
315 handlers::proto_json::period_change_rank(&client, c2s).await
316 },
317 )
318 .await
319 }
320
321 async fn futu_get_high_dividend_soe_rank_impl(
322 &self,
323 Parameters(req): Parameters<ProtoJsonReq>,
324 req_ctx: RequestContext<RoleServer>,
325 ) -> std::result::Result<String, String> {
326 run_qot_proto_json::<futu_proto::qot_get_high_dividend_soe_rank::C2s, _, _>(
327 self,
328 "futu_get_high_dividend_soe_rank",
329 "high-dividend-soe-rank",
330 req,
331 req_ctx,
332 |client, c2s| async move {
333 handlers::proto_json::high_dividend_soe_rank(&client, c2s).await
334 },
335 )
336 .await
337 }
338
339 async fn futu_get_institution_list_impl(
340 &self,
341 Parameters(req): Parameters<ProtoJsonReq>,
342 req_ctx: RequestContext<RoleServer>,
343 ) -> std::result::Result<String, String> {
344 run_qot_proto_json::<futu_proto::qot_get_institution_list::C2s, _, _>(
345 self,
346 "futu_get_institution_list",
347 "institution-list",
348 req,
349 req_ctx,
350 |client, c2s| async move { handlers::proto_json::institution_list(&client, c2s).await },
351 )
352 .await
353 }
354
355 async fn futu_get_institution_profile_impl(
356 &self,
357 Parameters(req): Parameters<ProtoJsonReq>,
358 req_ctx: RequestContext<RoleServer>,
359 ) -> std::result::Result<String, String> {
360 run_qot_proto_json::<futu_proto::qot_get_institution_profile::C2s, _, _>(
361 self,
362 "futu_get_institution_profile",
363 "institution-profile",
364 req,
365 req_ctx,
366 |client, c2s| async move {
367 handlers::proto_json::institution_profile(&client, c2s).await
368 },
369 )
370 .await
371 }
372
373 async fn futu_get_institution_distribution_impl(
374 &self,
375 Parameters(req): Parameters<ProtoJsonReq>,
376 req_ctx: RequestContext<RoleServer>,
377 ) -> std::result::Result<String, String> {
378 run_qot_proto_json::<futu_proto::qot_get_institution_distribution::C2s, _, _>(
379 self,
380 "futu_get_institution_distribution",
381 "institution-distribution",
382 req,
383 req_ctx,
384 |client, c2s| async move {
385 handlers::proto_json::institution_distribution(&client, c2s).await
386 },
387 )
388 .await
389 }
390
391 async fn futu_get_institution_holding_change_impl(
392 &self,
393 Parameters(req): Parameters<ProtoJsonReq>,
394 req_ctx: RequestContext<RoleServer>,
395 ) -> std::result::Result<String, String> {
396 run_qot_proto_json::<futu_proto::qot_get_institution_holding_change::C2s, _, _>(
397 self,
398 "futu_get_institution_holding_change",
399 "institution-holding-change",
400 req,
401 req_ctx,
402 |client, c2s| async move {
403 handlers::proto_json::institution_holding_change(&client, c2s).await
404 },
405 )
406 .await
407 }
408
409 async fn futu_get_institution_holding_list_impl(
410 &self,
411 Parameters(req): Parameters<ProtoJsonReq>,
412 req_ctx: RequestContext<RoleServer>,
413 ) -> std::result::Result<String, String> {
414 run_qot_proto_json::<futu_proto::qot_get_institution_holding_list::C2s, _, _>(
415 self,
416 "futu_get_institution_holding_list",
417 "institution-holding-list",
418 req,
419 req_ctx,
420 |client, c2s| async move {
421 handlers::proto_json::institution_holding_list(&client, c2s).await
422 },
423 )
424 .await
425 }
426
427 async fn futu_get_ark_fund_holding_impl(
428 &self,
429 Parameters(req): Parameters<ProtoJsonReq>,
430 req_ctx: RequestContext<RoleServer>,
431 ) -> std::result::Result<String, String> {
432 run_qot_proto_json::<futu_proto::qot_get_ark_fund_holding::C2s, _, _>(
433 self,
434 "futu_get_ark_fund_holding",
435 "ark-fund-holding",
436 req,
437 req_ctx,
438 |client, c2s| async move { handlers::proto_json::ark_fund_holding(&client, c2s).await },
439 )
440 .await
441 }
442
443 async fn futu_get_ark_stock_dynamic_impl(
444 &self,
445 Parameters(req): Parameters<ProtoJsonReq>,
446 req_ctx: RequestContext<RoleServer>,
447 ) -> std::result::Result<String, String> {
448 run_qot_proto_json::<futu_proto::qot_get_ark_stock_dynamic::C2s, _, _>(
449 self,
450 "futu_get_ark_stock_dynamic",
451 "ark-stock-dynamic",
452 req,
453 req_ctx,
454 |client, c2s| async move { handlers::proto_json::ark_stock_dynamic(&client, c2s).await },
455 )
456 .await
457 }
458
459 async fn futu_get_ark_active_transaction_impl(
460 &self,
461 Parameters(req): Parameters<ProtoJsonReq>,
462 req_ctx: RequestContext<RoleServer>,
463 ) -> std::result::Result<String, String> {
464 run_qot_proto_json::<futu_proto::qot_get_ark_active_transaction::C2s, _, _>(
465 self,
466 "futu_get_ark_active_transaction",
467 "ark-active-transaction",
468 req,
469 req_ctx,
470 |client, c2s| async move {
471 handlers::proto_json::ark_active_transaction(&client, c2s).await
472 },
473 )
474 .await
475 }
476
477 async fn futu_get_rating_change_impl(
478 &self,
479 Parameters(req): Parameters<ProtoJsonReq>,
480 req_ctx: RequestContext<RoleServer>,
481 ) -> std::result::Result<String, String> {
482 run_qot_proto_json::<futu_proto::qot_get_rating_change::C2s, _, _>(
483 self,
484 "futu_get_rating_change",
485 "rating-change",
486 req,
487 req_ctx,
488 |client, c2s| async move { handlers::proto_json::rating_change(&client, c2s).await },
489 )
490 .await
491 }
492
493 async fn futu_get_industrial_chain_list_impl(
494 &self,
495 Parameters(req): Parameters<ProtoJsonReq>,
496 req_ctx: RequestContext<RoleServer>,
497 ) -> std::result::Result<String, String> {
498 run_qot_proto_json::<futu_proto::qot_get_industrial_chain_list::C2s, _, _>(
499 self,
500 "futu_get_industrial_chain_list",
501 "industrial-chain-list",
502 req,
503 req_ctx,
504 |client, c2s| async move {
505 handlers::proto_json::industrial_chain_list(&client, c2s).await
506 },
507 )
508 .await
509 }
510
511 async fn futu_get_industrial_chain_detail_impl(
512 &self,
513 Parameters(req): Parameters<ProtoJsonReq>,
514 req_ctx: RequestContext<RoleServer>,
515 ) -> std::result::Result<String, String> {
516 run_qot_proto_json::<futu_proto::qot_get_industrial_chain_detail::C2s, _, _>(
517 self,
518 "futu_get_industrial_chain_detail",
519 "industrial-chain-detail",
520 req,
521 req_ctx,
522 |client, c2s| async move {
523 handlers::proto_json::industrial_chain_detail(&client, c2s).await
524 },
525 )
526 .await
527 }
528
529 async fn futu_get_industrial_chain_by_plate_impl(
530 &self,
531 Parameters(req): Parameters<ProtoJsonReq>,
532 req_ctx: RequestContext<RoleServer>,
533 ) -> std::result::Result<String, String> {
534 run_qot_proto_json::<futu_proto::qot_get_industrial_chain_by_plate::C2s, _, _>(
535 self,
536 "futu_get_industrial_chain_by_plate",
537 "industrial-chain-by-plate",
538 req,
539 req_ctx,
540 |client, c2s| async move {
541 handlers::proto_json::industrial_chain_by_plate(&client, c2s).await
542 },
543 )
544 .await
545 }
546
547 async fn futu_get_industrial_plate_info_impl(
548 &self,
549 Parameters(req): Parameters<ProtoJsonReq>,
550 req_ctx: RequestContext<RoleServer>,
551 ) -> std::result::Result<String, String> {
552 run_qot_proto_json::<futu_proto::qot_get_industrial_plate_info::C2s, _, _>(
553 self,
554 "futu_get_industrial_plate_info",
555 "industrial-plate-info",
556 req,
557 req_ctx,
558 |client, c2s| async move {
559 handlers::proto_json::industrial_plate_info(&client, c2s).await
560 },
561 )
562 .await
563 }
564
565 async fn futu_get_industrial_plate_stock_impl(
566 &self,
567 Parameters(req): Parameters<ProtoJsonReq>,
568 req_ctx: RequestContext<RoleServer>,
569 ) -> std::result::Result<String, String> {
570 run_qot_proto_json::<futu_proto::qot_get_industrial_plate_stock::C2s, _, _>(
571 self,
572 "futu_get_industrial_plate_stock",
573 "industrial-plate-stock",
574 req,
575 req_ctx,
576 |client, c2s| async move {
577 handlers::proto_json::industrial_plate_stock(&client, c2s).await
578 },
579 )
580 .await
581 }
582
583 async fn futu_get_heat_map_data_impl(
584 &self,
585 Parameters(req): Parameters<ProtoJsonReq>,
586 req_ctx: RequestContext<RoleServer>,
587 ) -> std::result::Result<String, String> {
588 run_qot_proto_json::<futu_proto::qot_get_heat_map_data::C2s, _, _>(
589 self,
590 "futu_get_heat_map_data",
591 "heat-map-data",
592 req,
593 req_ctx,
594 |client, c2s| async move { handlers::proto_json::heat_map_data(&client, c2s).await },
595 )
596 .await
597 }
598
599 async fn futu_get_rise_fall_distribution_impl(
600 &self,
601 Parameters(req): Parameters<ProtoJsonReq>,
602 req_ctx: RequestContext<RoleServer>,
603 ) -> std::result::Result<String, String> {
604 run_qot_proto_json::<futu_proto::qot_get_rise_fall_distribution::C2s, _, _>(
605 self,
606 "futu_get_rise_fall_distribution",
607 "rise-fall-distribution",
608 req,
609 req_ctx,
610 |client, c2s| async move {
611 handlers::proto_json::rise_fall_distribution(&client, c2s).await
612 },
613 )
614 .await
615 }
616}
617
618include!(concat!(
619 env!("OUT_DIR"),
620 "/generated_mcp_routes_qot_3401_plus.rs"
621));