lean_ctx/tools/registered/
ctx_expand.rs1use rmcp::ErrorData;
2use rmcp::model::Tool;
3use serde_json::{Map, Value, json};
4
5use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput};
6use crate::tool_defs::tool_def;
7
8pub struct CtxExpandTool;
9
10impl McpTool for CtxExpandTool {
11 fn name(&self) -> &'static str {
12 "ctx_expand"
13 }
14
15 fn tool_def(&self) -> Tool {
16 tool_def(
17 "ctx_expand",
18 "Retrieve archived tool output by ID (e.g. id=@F1 from [Archived:ID] hints).\n\
19 WORKFLOW: see [Archived:ID] → ctx_expand id=ID to restore full content.\n\
20 Supports head/tail/search to filter lines and save tokens on re-read.\n\
21 action=list browses all archives. action=search_all queries across archives.\n\
22 Zero-loss: original preserved.\n\
23 NO MCP? The same bytes are a real file — every [Archived]/tee/firewall hint\n\
24 shows its on-disk path; read that path directly with any tool instead.\n\
25 ANTIPATTERN: not for reading project files — use ctx_read or ctx_compose.",
26 json!({
27 "type": "object",
28 "properties": {
29 "id": { "type": "string", "description": "Archive ID or @F1 ref" },
30 "action": { "type": "string", "description": "retrieve|list|search_all" },
31 "start_line": { "type": "integer", "description": "1-based start line" },
32 "end_line": { "type": "integer", "description": "1-based end line" },
33 "head": { "type": "integer", "description": "First N lines" },
34 "tail": { "type": "integer", "description": "Last N lines" },
35 "search": { "type": "string", "description": "Lines matching substring" },
36 "json_keys": { "type": "boolean", "description": "List JSON keys" },
37 "json_path": { "type": "string", "description": "JSON path, e.g. data.items.0" },
38 "query": { "type": "string", "description": "search_all query" },
39 "session_id": { "type": "string", "description": "Filter by session ID" }
40 }
41 }),
42 )
43 }
44
45 fn handle(
46 &self,
47 args: &Map<String, Value>,
48 _ctx: &ToolContext,
49 ) -> Result<ToolOutput, ErrorData> {
50 let args_val = Value::Object(args.clone());
51 let result = crate::tools::ctx_expand::handle(&args_val);
52 Ok(ToolOutput::simple(result))
53 }
54}