Skip to main content

futu_mcp/tools/
kline_pattern.rs

1//! MCP proto-JSON tools for source-pinned v1.8 K-line pattern reads.
2
3use 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<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(error) => return FutuServer::tool_err(error),
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
38macro_rules! tool_impl {
39    ($method:ident, $module:ident, $tool:literal, $label:literal, $handler:ident) => {
40        impl FutuServer {
41            async fn $method(
42                &self,
43                Parameters(req): Parameters<ProtoJsonReq>,
44                req_ctx: RequestContext<RoleServer>,
45            ) -> std::result::Result<String, String> {
46                run::<futu_proto::$module::C2s, _, _>(
47                    self,
48                    $tool,
49                    $label,
50                    req,
51                    req_ctx,
52                    |client, c2s| async move { handlers::proto_json::$handler(&client, c2s).await },
53                )
54                .await
55            }
56        }
57    };
58}
59
60tool_impl!(
61    futu_get_kline_pattern_impl,
62    qot_get_kline_pattern,
63    "futu_get_kline_pattern",
64    "kline-pattern",
65    kline_pattern
66);
67tool_impl!(
68    futu_get_kline_pattern_statistics_impl,
69    qot_get_kline_pattern_statistics,
70    "futu_get_kline_pattern_statistics",
71    "kline-pattern-statistics",
72    kline_pattern_statistics
73);
74tool_impl!(
75    futu_get_kline_pattern_stocks_impl,
76    qot_get_kline_pattern_stocks,
77    "futu_get_kline_pattern_stocks",
78    "kline-pattern-stocks",
79    kline_pattern_stocks
80);
81tool_impl!(
82    futu_get_kline_pattern_performance_impl,
83    qot_get_kline_pattern_performance,
84    "futu_get_kline_pattern_performance",
85    "kline-pattern-performance",
86    kline_pattern_performance
87);
88tool_impl!(
89    futu_get_kline_pattern_catalog_impl,
90    qot_get_kline_pattern_catalog,
91    "futu_get_kline_pattern_catalog",
92    "kline-pattern-catalog",
93    kline_pattern_catalog
94);
95
96include!(concat!(
97    env!("OUT_DIR"),
98    "/generated_mcp_routes_kline_pattern.rs"
99));