Skip to main content

futu_mcp/tools/
system.rs

1//! MCP system/core tools.
2
3use 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        // MED-2 修(code review):scope 拒绝是 auth error,用 Err 让 rmcp set
24        // is_error=true,agent 通过 top-level envelope 识别权限问题
25        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"));