1use std::future::Future;
2use std::sync::Arc;
3
4use futu_net::client::FutuClient;
5use rmcp::{RoleServer, handler::server::wrapper::Parameters, service::RequestContext};
6use serde::de::DeserializeOwned;
7
8use crate::handlers;
9use crate::tool_args::ProtoJsonReq;
10
11use super::FutuServer;
12
13async fn run<C2s, F, Fut>(
14 server: &FutuServer,
15 tool_name: &'static str,
16 label: &'static str,
17 req: ProtoJsonReq,
18 req_ctx: RequestContext<RoleServer>,
19 handler: F,
20) -> std::result::Result<String, String>
21where
22 C2s: DeserializeOwned,
23 F: FnOnce(Arc<FutuClient>, C2s) -> Fut,
24 Fut: Future<Output = anyhow::Result<String>>,
25{
26 let c2s = match handlers::proto_json::parse_c2s_json::<C2s>(label, &req.c2s_json) {
27 Ok(c2s) => c2s,
28 Err(error) => return FutuServer::tool_err(error),
29 };
30 let client = server
31 .read_client_or_err(tool_name, &req_ctx, req.api_key.as_deref(), None)
32 .await?;
33 FutuServer::wrap_result(handler(client, c2s).await)
34}
35
36impl FutuServer {
37 async fn futu_get_option_market_statistic_impl(
38 &self,
39 Parameters(req): Parameters<ProtoJsonReq>,
40 req_ctx: RequestContext<RoleServer>,
41 ) -> std::result::Result<String, String> {
42 run::<futu_proto::qot_get_option_market_statistic::C2s, _, _>(
43 self,
44 "futu_get_option_market_statistic",
45 "option-market-statistic",
46 req,
47 req_ctx,
48 |client, c2s| async move {
49 handlers::proto_json::option_market_statistic(&client, c2s).await
50 },
51 )
52 .await
53 }
54
55 async fn futu_get_option_underlying_his_statistic_impl(
56 &self,
57 Parameters(req): Parameters<ProtoJsonReq>,
58 req_ctx: RequestContext<RoleServer>,
59 ) -> std::result::Result<String, String> {
60 run::<futu_proto::qot_get_option_underlying_his_statistic::C2s, _, _>(
61 self,
62 "futu_get_option_underlying_his_statistic",
63 "option-underlying-his-statistic",
64 req,
65 req_ctx,
66 |client, c2s| async move {
67 handlers::proto_json::option_underlying_his_statistic(&client, c2s).await
68 },
69 )
70 .await
71 }
72
73 async fn futu_get_option_underlying_overview_impl(
74 &self,
75 Parameters(req): Parameters<ProtoJsonReq>,
76 req_ctx: RequestContext<RoleServer>,
77 ) -> std::result::Result<String, String> {
78 run::<futu_proto::qot_get_option_underlying_overview::C2s, _, _>(
79 self,
80 "futu_get_option_underlying_overview",
81 "option-underlying-overview",
82 req,
83 req_ctx,
84 |client, c2s| async move {
85 handlers::proto_json::option_underlying_overview(&client, c2s).await
86 },
87 )
88 .await
89 }
90
91 async fn futu_get_option_underlying_his_volatility_impl(
92 &self,
93 Parameters(req): Parameters<ProtoJsonReq>,
94 req_ctx: RequestContext<RoleServer>,
95 ) -> std::result::Result<String, String> {
96 run::<futu_proto::qot_get_option_underlying_his_volatility::C2s, _, _>(
97 self,
98 "futu_get_option_underlying_his_volatility",
99 "option-underlying-his-volatility",
100 req,
101 req_ctx,
102 |client, c2s| async move {
103 handlers::proto_json::option_underlying_his_volatility(&client, c2s).await
104 },
105 )
106 .await
107 }
108
109 async fn futu_get_option_underlying_rank_impl(
110 &self,
111 Parameters(req): Parameters<ProtoJsonReq>,
112 req_ctx: RequestContext<RoleServer>,
113 ) -> std::result::Result<String, String> {
114 run::<futu_proto::qot_get_option_underlying_rank::C2s, _, _>(
115 self,
116 "futu_get_option_underlying_rank",
117 "option-underlying-rank",
118 req,
119 req_ctx,
120 |client, c2s| async move {
121 handlers::proto_json::option_underlying_rank(&client, c2s).await
122 },
123 )
124 .await
125 }
126
127 async fn futu_get_option_rank_impl(
128 &self,
129 Parameters(req): Parameters<ProtoJsonReq>,
130 req_ctx: RequestContext<RoleServer>,
131 ) -> std::result::Result<String, String> {
132 run::<futu_proto::qot_get_option_rank::C2s, _, _>(
133 self,
134 "futu_get_option_rank",
135 "option-rank",
136 req,
137 req_ctx,
138 |client, c2s| async move { handlers::proto_json::option_rank(&client, c2s).await },
139 )
140 .await
141 }
142
143 async fn futu_get_option_event_impl(
144 &self,
145 Parameters(req): Parameters<ProtoJsonReq>,
146 req_ctx: RequestContext<RoleServer>,
147 ) -> std::result::Result<String, String> {
148 run::<futu_proto::qot_get_option_event::C2s, _, _>(
149 self,
150 "futu_get_option_event",
151 "option-event",
152 req,
153 req_ctx,
154 |client, c2s| async move { handlers::proto_json::option_event(&client, c2s).await },
155 )
156 .await
157 }
158
159 async fn futu_get_option_event_alert_impl(
160 &self,
161 Parameters(req): Parameters<ProtoJsonReq>,
162 req_ctx: RequestContext<RoleServer>,
163 ) -> std::result::Result<String, String> {
164 run::<futu_proto::qot_get_option_event_alert::C2s, _, _>(self, "futu_get_option_event_alert", "option-event-alert", req, req_ctx, |client, c2s| async move { handlers::proto_json::option_event_alert(&client, c2s).await }).await
165 }
166
167 async fn futu_set_option_event_alert_impl(
168 &self,
169 Parameters(req): Parameters<ProtoJsonReq>,
170 req_ctx: RequestContext<RoleServer>,
171 ) -> std::result::Result<String, String> {
172 run::<futu_proto::qot_set_option_event_alert::C2s, _, _>(
173 self,
174 "futu_set_option_event_alert",
175 "set-option-event-alert",
176 req,
177 req_ctx,
178 |client, c2s| async move {
179 handlers::proto_json::set_option_event_alert(&client, c2s).await
180 },
181 )
182 .await
183 }
184
185 async fn futu_get_option_zero_dte_screener_impl(
186 &self,
187 Parameters(req): Parameters<ProtoJsonReq>,
188 req_ctx: RequestContext<RoleServer>,
189 ) -> std::result::Result<String, String> {
190 run::<futu_proto::qot_get_option_zero_dte_screener::C2s, _, _>(
191 self,
192 "futu_get_option_zero_dte_screener",
193 "option-zero-dte-screener",
194 req,
195 req_ctx,
196 |client, c2s| async move {
197 handlers::proto_json::option_zero_dte_screener(&client, c2s).await
198 },
199 )
200 .await
201 }
202
203 async fn futu_get_option_zero_dte_contract_impl(
204 &self,
205 Parameters(req): Parameters<ProtoJsonReq>,
206 req_ctx: RequestContext<RoleServer>,
207 ) -> std::result::Result<String, String> {
208 run::<futu_proto::qot_get_option_zero_dte_contract::C2s, _, _>(
209 self,
210 "futu_get_option_zero_dte_contract",
211 "option-zero-dte-contract",
212 req,
213 req_ctx,
214 |client, c2s| async move {
215 handlers::proto_json::option_zero_dte_contract(&client, c2s).await
216 },
217 )
218 .await
219 }
220
221 async fn futu_get_option_earnings_screener_impl(
222 &self,
223 Parameters(req): Parameters<ProtoJsonReq>,
224 req_ctx: RequestContext<RoleServer>,
225 ) -> std::result::Result<String, String> {
226 run::<futu_proto::qot_get_option_earnings_screener::C2s, _, _>(
227 self,
228 "futu_get_option_earnings_screener",
229 "option-earnings-screener",
230 req,
231 req_ctx,
232 |client, c2s| async move {
233 handlers::proto_json::option_earnings_screener(&client, c2s).await
234 },
235 )
236 .await
237 }
238
239 async fn futu_get_option_seller_screener_impl(
240 &self,
241 Parameters(req): Parameters<ProtoJsonReq>,
242 req_ctx: RequestContext<RoleServer>,
243 ) -> std::result::Result<String, String> {
244 run::<futu_proto::qot_get_option_seller_screener::C2s, _, _>(
245 self,
246 "futu_get_option_seller_screener",
247 "option-seller-screener",
248 req,
249 req_ctx,
250 |client, c2s| async move {
251 handlers::proto_json::option_seller_screener(&client, c2s).await
252 },
253 )
254 .await
255 }
256}
257
258include!(concat!(
259 env!("OUT_DIR"),
260 "/generated_mcp_routes_option_analytics.rs"
261));