lean_ctx_server/tools/registered/
ctx_context.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 CtxContextTool;
10
11impl McpTool for CtxContextTool {
12 fn name(&self) -> &'static str {
13 "ctx_context"
14 }
15
16 fn tool_def(&self) -> Tool {
17 tool_def(
18 "ctx_context",
19 "Session context overview — cached files, seen files, session state, CRP mode.\n\
20 WORKFLOW: track context budget periodically — use before ctx_compress or ctx_control(action=\"evict\").\n\
21 ANTIPATTERN: not for reading file content — use ctx_read or ctx_compose.",
22 json!({
23 "type": "object",
24 "properties": {}
25 }),
26 )
27 }
28
29 fn handle(
30 &self,
31 _args: &Map<String, Value>,
32 ctx: &ToolContext,
33 ) -> Result<ToolOutput, ErrorData> {
34 let cache = ctx
35 .cache
36 .as_ref()
37 .ok_or_else(|| ErrorData::internal_error("cache not available", None))?;
38 let Some(guard) = crate::server::bounded_lock::read(cache, "ctx_context") else {
39 return Ok(ToolOutput::simple(
40 "[context status temporarily unavailable — retry]".to_string(),
41 ));
42 };
43 let turn = ctx
44 .call_count
45 .as_ref()
46 .map_or(0, |c| c.load(std::sync::atomic::Ordering::Relaxed));
47 let result = crate::tools::ctx_context::handle_status(&guard, turn, ctx.crp_mode);
48 Ok(ToolOutput::simple(result))
49 }
50}