Skip to main content

lean_ctx/tools/registered/
ctx_callgraph.rs

1use rmcp::model::Tool;
2use rmcp::ErrorData;
3use serde_json::{json, Map, Value};
4
5use crate::server::tool_trait::{get_int, get_str, McpTool, ToolContext, ToolOutput};
6use crate::tool_defs::tool_def;
7
8pub struct CtxCallgraphTool;
9
10impl McpTool for CtxCallgraphTool {
11    fn name(&self) -> &'static str {
12        "ctx_callgraph"
13    }
14
15    fn tool_def(&self) -> Tool {
16        tool_def(
17            "ctx_callgraph",
18            "Call graph query: callers/callees (multi-hop BFS), trace path between symbols, risk classification by caller count.",
19            json!({
20                "type": "object",
21                "properties": {
22                    "action": {
23                        "type": "string",
24                        "description": "callers|callees|trace|risk (default: callers)",
25                        "enum": ["callers", "callees", "trace", "risk"]
26                    },
27                    "symbol": {
28                        "type": "string",
29                        "description": "Symbol name (required for callers/callees/risk)"
30                    },
31                    "direction": {
32                        "type": "string",
33                        "description": "Deprecated — use action instead. callers|callees"
34                    },
35                    "file": {
36                        "type": "string",
37                        "description": "Optional: scope results to a specific file"
38                    },
39                    "depth": {
40                        "type": "integer",
41                        "description": "BFS depth for callers/callees (1–5, default 1)",
42                        "minimum": 1,
43                        "maximum": 5
44                    },
45                    "from": {
46                        "type": "string",
47                        "description": "Source symbol for trace action"
48                    },
49                    "to": {
50                        "type": "string",
51                        "description": "Target symbol for trace action"
52                    }
53                }
54            }),
55        )
56    }
57
58    fn handle(
59        &self,
60        args: &Map<String, Value>,
61        ctx: &ToolContext,
62    ) -> Result<ToolOutput, ErrorData> {
63        let action = get_str(args, "action")
64            .or_else(|| get_str(args, "direction"))
65            .unwrap_or_else(|| "callers".to_string());
66
67        let action_normalized = match action.to_lowercase().as_str() {
68            "callers" | "caller" => "callers",
69            "callees" | "callee" => "callees",
70            "trace" => "trace",
71            "risk" => "risk",
72            _ => action.as_str(),
73        }
74        .to_string();
75
76        let symbol = get_str(args, "symbol");
77        let file = get_str(args, "file");
78        let depth = get_int(args, "depth").unwrap_or(1).clamp(1, 5) as usize;
79        let from = get_str(args, "from");
80        let to = get_str(args, "to");
81
82        let result = crate::tools::ctx_callgraph::handle(
83            &action_normalized,
84            symbol.as_deref(),
85            file.as_deref(),
86            &ctx.project_root,
87            depth,
88            from.as_deref(),
89            to.as_deref(),
90        );
91
92        Ok(ToolOutput {
93            text: result,
94            original_tokens: 0,
95            saved_tokens: 0,
96            mode: Some(action_normalized),
97            path: None,
98            changed: false,
99        })
100    }
101}