lean_ctx/tools/registered/
ctx_package.rs1use rmcp::model::Tool;
2use rmcp::ErrorData;
3use serde_json::{json, Map, Value};
4
5use crate::server::tool_trait::{get_str, McpTool, ToolContext, ToolOutput};
6use crate::tool_defs::tool_def;
7
8pub struct CtxPackageTool;
9
10impl McpTool for CtxPackageTool {
11 fn name(&self) -> &'static str {
12 "ctx_package"
13 }
14
15 fn tool_def(&self) -> Tool {
16 tool_def(
17 "ctx_package",
18 "Save or resume portable context packages — self-contained JSON bundles with session state, summaries, and knowledge. Use to hand off context between agents, persist session snapshots for later, or onboard a new agent into a previous session's context. Actions: save (export current session), resume (import from a package file), list (show saved packages), info (inspect a package without importing).",
19 json!({
20 "type": "object",
21 "properties": {
22 "action": {
23 "type": "string",
24 "enum": ["save", "resume", "list", "info"],
25 "description": "Package action (default: save)"
26 },
27 "path": {
28 "type": "string",
29 "description": "File path for resume/info, or custom output path for save"
30 },
31 "description": {
32 "type": "string",
33 "description": "Human-readable description for the saved package"
34 }
35 },
36 "required": []
37 }),
38 )
39 }
40
41 fn handle(
42 &self,
43 args: &Map<String, Value>,
44 ctx: &ToolContext,
45 ) -> Result<ToolOutput, ErrorData> {
46 let action = get_str(args, "action").unwrap_or_else(|| "save".to_string());
47 let path = get_str(args, "path");
48 let description = get_str(args, "description");
49
50 let guard = ctx
51 .session
52 .as_ref()
53 .and_then(|s| crate::server::bounded_lock::read(s, "ctx_package:session"));
54 let session_ref = guard.as_deref();
55 let root = session_ref
56 .and_then(|s| s.project_root.clone())
57 .unwrap_or_else(|| ctx.project_root.clone());
58
59 let agent_id_guard = ctx.agent_id.as_ref().map(|a| a.blocking_read());
60 let agent_id = agent_id_guard.as_ref().and_then(|g| g.as_deref());
61 let result = crate::tools::ctx_package::handle(
62 &root,
63 session_ref,
64 &action,
65 path.as_deref(),
66 agent_id,
67 description.as_deref(),
68 );
69 Ok(ToolOutput::simple(result))
70 }
71}