Skip to main content

futu_mcp/tools/
search.rs

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_search<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_search_quote_impl(
38        &self,
39        Parameters(req): Parameters<ProtoJsonReq>,
40        req_ctx: RequestContext<RoleServer>,
41    ) -> std::result::Result<String, String> {
42        run_search::<futu_proto::qot_get_search_quote::C2s, _, _>(
43            self,
44            "futu_search_quote",
45            "search-quote",
46            req,
47            req_ctx,
48            |client, c2s| async move { handlers::proto_json::search_quote(&client, c2s).await },
49        )
50        .await
51    }
52
53    async fn futu_search_news_impl(
54        &self,
55        Parameters(req): Parameters<ProtoJsonReq>,
56        req_ctx: RequestContext<RoleServer>,
57    ) -> std::result::Result<String, String> {
58        run_search::<futu_proto::qot_get_search_news::C2s, _, _>(
59            self,
60            "futu_search_news",
61            "search-news",
62            req,
63            req_ctx,
64            |client, c2s| async move { handlers::proto_json::search_news(&client, c2s).await },
65        )
66        .await
67    }
68}
69
70include!(concat!(env!("OUT_DIR"), "/generated_mcp_routes_search.rs"));