lean_ctx_server/tools/registered/
ctx_radar.rs1use rmcp::ErrorData;
3use rmcp::model::Tool;
4use serde_json::{Map, Value, json};
5
6use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput};
7use lean_ctx::tool_defs::tool_def;
8
9pub struct CtxRadarTool;
10
11impl McpTool for CtxRadarTool {
12 fn name(&self) -> &'static str {
13 "ctx_radar"
14 }
15
16 fn tool_def(&self) -> Tool {
17 tool_def(
18 "ctx_radar",
19 "Context budget breakdown — system prompt, messages, tools, reads, shell.\n\
20 WORKFLOW: call when context window tight to find biggest consumers.\n\
21 ANTIPATTERN: not for per-call timing — use ctx_metrics instead.\n\
22 format=display (human-readable) or json (structured). Complements ctx_metrics\n\
23 for comprehensive budget analysis. Saves tokens vs manual budget estimation.",
24 json!({
25 "type": "object",
26 "properties": {
27 "format": {
28 "type": "string",
29 "description": "display|json",
30 "enum": ["display", "json"],
31 "default": "display"
32 }
33 }
34 }),
35 )
36 }
37
38 fn handle(
39 &self,
40 args: &Map<String, Value>,
41 ctx: &ToolContext,
42 ) -> Result<ToolOutput, ErrorData> {
43 let format = args
44 .get("format")
45 .and_then(|v| v.as_str())
46 .unwrap_or("display");
47
48 let data_dir = lean_ctx::core::data_dir::lean_ctx_data_dir().unwrap_or_else(|_| {
49 std::path::PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()))
50 .join(".lean-ctx")
51 });
52
53 let client_name = ctx
54 .client_name
55 .as_ref()
56 .and_then(|cn| tokio::task::block_in_place(|| cn.blocking_read().clone()).into())
57 .unwrap_or_else(|| "cursor".to_string());
58 let window_size = lean_ctx::core::context_radar::default_window_for_client(&client_name);
59
60 let radar = lean_ctx::core::context_radar::ContextRadar::load(&data_dir, window_size);
61
62 let output = match format {
63 "json" => {
64 let breakdown = radar.budget_breakdown();
65 serde_json::to_string_pretty(&breakdown).unwrap_or_default()
66 }
67 _ => radar.format_display(),
68 };
69
70 Ok(ToolOutput::simple(output))
71 }
72}