lean_ctx_server/tools/registered/
ctx_heatmap.rs1use rmcp::ErrorData;
3use rmcp::model::Tool;
4use serde_json::{Map, Value, json};
5
6use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput, get_str};
7use lean_ctx::tool_defs::tool_def;
8
9pub struct CtxHeatmapTool;
10
11impl McpTool for CtxHeatmapTool {
12 fn name(&self) -> &'static str {
13 "ctx_heatmap"
14 }
15
16 fn tool_def(&self) -> Tool {
17 tool_def(
18 "ctx_heatmap",
19 "File access heatmap — shows most frequently accessed files per session.\n\
20 action=status (default) for summary, action=detail for per-file access counts.\n\
21 Identify hot files to optimize context usage.",
22 json!({
23 "type": "object",
24 "properties": {
25 "action": { "type": "string", "description": "status|detail" },
26 "path": { "type": "string" }
27 }
28 }),
29 )
30 }
31
32 fn handle(
33 &self,
34 args: &Map<String, Value>,
35 ctx: &ToolContext,
36 ) -> Result<ToolOutput, ErrorData> {
37 let action = get_str(args, "action").unwrap_or_else(|| "status".to_string());
38 let path = get_str(args, "path")
39 .map(|raw| lean_ctx::core::workspace_authority::confine(&raw, &ctx.project_root, false))
40 .transpose()
41 .map_err(|error| ErrorData::invalid_params(error, None))?;
42 let result = crate::tools::ctx_heatmap::handle(&action, path.as_deref());
43 Ok(ToolOutput {
44 text: result,
45 original_tokens: 0,
46 saved_tokens: 0,
47 mode: Some(action),
48 path: None,
49 changed: false,
50 shell_outcome: None,
51 content_blocks: None,
52 })
53 }
54}