lean_ctx/tools/registered/
ctx_impact.rs1use rmcp::ErrorData;
2use rmcp::model::Tool;
3use serde_json::{Map, Value, json};
4
5use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput, get_str, get_usize};
6use crate::tool_defs::tool_def;
7
8pub struct CtxImpactTool;
9
10impl McpTool for CtxImpactTool {
11 fn name(&self) -> &'static str {
12 "ctx_impact"
13 }
14
15 fn tool_def(&self) -> Tool {
16 tool_def(
17 "ctx_impact",
18 "Change impact analysis — assess blast radius before refactoring.\n\
19 action=analyze path=\"file.rs\" maps downstream dependents; action=diff compares git refs;\n\
20 action=chain traces from→to dependency paths. depth controls traversal (default 5).",
21 json!({
22 "type": "object",
23 "properties": {
24 "action": {
25 "type": "string",
26 "enum": ["analyze", "diff", "chain", "build", "update", "status"],
27 "description": "analyze|diff|chain|build|update|status"
28 },
29 "path": {
30 "type": "string",
31 "description": "File path or type name"
32 },
33 "root": {
34 "type": "string",
35 "description": "Project root"
36 },
37 "depth": {
38 "type": "integer",
39 "description": "Max depth (default: 5)"
40 },
41 "format": {
42 "type": "string",
43 "description": "Output format"
44 }
45 }
46 }),
47 )
48 }
49
50 fn handle(
51 &self,
52 args: &Map<String, Value>,
53 ctx: &ToolContext,
54 ) -> Result<ToolOutput, ErrorData> {
55 let action = get_str(args, "action").unwrap_or_else(|| "analyze".to_string());
56 let path = get_str(args, "path");
57 let depth = get_usize(args, "depth").map(|d| d.min(64));
58 let format = get_str(args, "format");
59 let root = if let Some(p) = ctx
60 .resolved_path("root")
61 .or(ctx.resolved_path("project_root"))
62 {
63 p
64 } else if let Some(err) = ctx.path_error("root").or(ctx.path_error("project_root")) {
65 return Err(ErrorData::invalid_params(format!("root: {err}"), None));
66 } else {
67 &ctx.project_root
68 };
69
70 let result = crate::tools::ctx_impact::handle(
71 &action,
72 path.as_deref(),
73 root,
74 depth,
75 format.as_deref(),
76 );
77
78 Ok(ToolOutput::simple(result))
79 }
80}