Skip to main content

lean_ctx_server/tools/registered/
ctx_dedup.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, get_str};
7use lean_ctx::tool_defs::tool_def;
8
9pub struct CtxDedupTool;
10
11impl McpTool for CtxDedupTool {
12    fn name(&self) -> &'static str {
13        "ctx_dedup"
14    }
15
16    fn tool_def(&self) -> Tool {
17        tool_def(
18            "ctx_dedup",
19            "WORKFLOW: action=analyze first to find shared imports/code across files, then action=apply to register dedup hints for ctx_read output.\n\
20            ANTIPATTERN: NOT for permanent dedup — only compression hints for read output.",
21            json!({
22                "type": "object",
23                "properties": {
24                    "action": {
25                        "type": "string",
26                        "description": "analyze (find shared) | apply (register dedup)",
27                        "default": "analyze"
28                    }
29                }
30            }),
31        )
32    }
33
34    fn handle(
35        &self,
36        args: &Map<String, Value>,
37        ctx: &ToolContext,
38    ) -> Result<ToolOutput, ErrorData> {
39        let action = get_str(args, "action").unwrap_or_default();
40        let cache = ctx
41            .cache
42            .as_ref()
43            .ok_or_else(|| ErrorData::internal_error("cache not available", None))?;
44        let result = if action == "apply" {
45            let Some(mut guard) = crate::server::bounded_lock::write(cache, "ctx_dedup:apply")
46            else {
47                return Ok(ToolOutput::simple(
48                    "[dedup unavailable — cache busy, retry]".to_string(),
49                ));
50            };
51            crate::tools::ctx_dedup::handle_action(&mut guard, &action)
52        } else {
53            let Some(guard) = crate::server::bounded_lock::read(cache, "ctx_dedup:status") else {
54                return Ok(ToolOutput::simple(
55                    "[dedup status unavailable — cache busy, retry]".to_string(),
56                ));
57            };
58            crate::tools::ctx_dedup::handle(&guard)
59        };
60        Ok(ToolOutput::simple(result))
61    }
62}