Skip to main content

lean_ctx_server/tools/registered/
ctx_context.rs

1// SPDX-License-Identifier: Apache-2.0
2use 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}