1use rmcp::{RoleServer, handler::server::wrapper::Parameters, service::RequestContext};
4
5use crate::handlers;
6use crate::tool_args::{NoArgs, ProtoJsonReq};
7
8use super::FutuServer;
9
10pub(crate) fn json_tool_output<T: serde::Serialize>(
11 tool: &str,
12 value: &T,
13) -> std::result::Result<String, String> {
14 serde_json::to_string_pretty(value).map_err(|e| format!("serialize {tool} output: {e}"))
15}
16
17impl FutuServer {
18 async fn futu_ping_impl(
19 &self,
20 Parameters(_req): Parameters<NoArgs>,
21 req_ctx: RequestContext<RoleServer>,
22 ) -> std::result::Result<String, String> {
23 self.require_acc_read_with_acc_id("futu_ping", &req_ctx, None, None)?;
26 let gateway = self.state.gateway().await;
27 let client = match self.state.client().await {
28 Ok(c) => c,
29 Err(e) => {
30 tracing::info!(tool = "futu_ping", ok = false, "connect failed: {e}");
31 return json_tool_output(
32 "futu_ping",
33 &handlers::core::PingOut {
34 gateway,
35 ok: false,
36 rtt_ms: 0.0,
37 message: format!("connect failed: {e}"),
38 },
39 );
40 }
41 };
42 let out = handlers::core::ping(&client, &gateway).await;
43 tracing::info!(tool = "futu_ping", ok = out.ok, rtt_ms = out.rtt_ms);
44 json_tool_output("futu_ping", &out)
45 }
46
47 async fn futu_verification_impl(
48 &self,
49 Parameters(req): Parameters<ProtoJsonReq>,
50 req_ctx: RequestContext<RoleServer>,
51 ) -> std::result::Result<String, String> {
52 self.require_acc_read_with_acc_id(
53 "futu_verification",
54 &req_ctx,
55 req.api_key.as_deref(),
56 None,
57 )?;
58 let c2s = handlers::proto_json::parse_c2s_json::<futu_proto::verification::C2s>(
59 "Verification",
60 &req.c2s_json,
61 )
62 .map_err(|error| error.to_string())?;
63 let client = self
64 .state
65 .verification_client()
66 .await
67 .map_err(|error| error.to_string())?;
68 handlers::core::verification(&client, c2s)
69 .await
70 .map_err(|error| error.to_string())
71 }
72}
73
74include!(concat!(env!("OUT_DIR"), "/generated_mcp_routes_system.rs"));