Skip to main content

lean_ctx/tools/registered/
ctx_task.rs

1use rmcp::ErrorData;
2use rmcp::model::Tool;
3use serde_json::{Map, Value, json};
4
5use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput, get_str};
6use crate::tool_defs::tool_def;
7
8pub struct CtxTaskTool;
9
10impl McpTool for CtxTaskTool {
11    fn name(&self) -> &'static str {
12        "ctx_task"
13    }
14
15    fn tool_def(&self) -> Tool {
16        tool_def(
17            "ctx_task",
18            "Multi-agent task orchestration.\n\
19             WORKFLOW: action=create → action=list to review → action=update to change state.\n\
20             Actions: create|update|list|get|cancel|message|info.\n\
21             States: working|input-required|completed|failed|canceled.\n\
22             ANTIPATTERN: not for code execution — use ctx_shell or ctx_execute.",
23            json!({
24                "type": "object",
25                "properties": {
26                    "action": {
27                        "type": "string",
28                        "enum": ["create", "update", "list", "get", "cancel", "message", "info"],
29                        "description": "create|update|list|get|cancel|message|info"
30                    },
31                    "task_id": { "type": "string", "description": "Task ID (for update|get|cancel|message)" },
32                    "to_agent": { "type": "string", "description": "Target agent ID (for create)" },
33                    "description": { "type": "string", "description": "Task description (for create)" },
34                    "state": { "type": "string", "description": "New state (working|input-required|completed|failed|canceled)" },
35                    "message": { "type": "string", "description": "Message or reason" }
36                },
37                "required": ["action"],
38                "allOf": [
39                    {
40                        "if": { "properties": { "action": { "const": "create" } }, "required": ["action"] },
41                        "then": { "required": ["action", "to_agent"] }
42                    },
43                    {
44                        "if": { "properties": { "action": { "const": "update" } }, "required": ["action"] },
45                        "then": { "required": ["action", "task_id", "state"] }
46                    },
47                    {
48                        "if": { "properties": { "action": { "const": "get" } }, "required": ["action"] },
49                        "then": { "required": ["action", "task_id"] }
50                    },
51                    {
52                        "if": { "properties": { "action": { "const": "cancel" } }, "required": ["action"] },
53                        "then": { "required": ["action", "task_id"] }
54                    },
55                    {
56                        "if": { "properties": { "action": { "const": "message" } }, "required": ["action"] },
57                        "then": { "required": ["action", "task_id", "message"] }
58                    }
59                ]
60            }),
61        )
62    }
63
64    fn handle(
65        &self,
66        args: &Map<String, Value>,
67        ctx: &ToolContext,
68    ) -> Result<ToolOutput, ErrorData> {
69        let action = get_str(args, "action").unwrap_or_else(|| "list".to_string());
70        let current_agent_id = ctx
71            .agent_id
72            .as_ref()
73            .map(|a| a.blocking_read().clone())
74            .unwrap_or_default();
75        let task_id = get_str(args, "task_id");
76        let to_agent = get_str(args, "to_agent");
77        let description = get_str(args, "description");
78        let state = get_str(args, "state");
79        let message = get_str(args, "message");
80
81        let result = crate::tools::ctx_task::handle(
82            &action,
83            current_agent_id.as_deref(),
84            task_id.as_deref(),
85            to_agent.as_deref(),
86            description.as_deref(),
87            state.as_deref(),
88            message.as_deref(),
89        );
90
91        Ok(ToolOutput {
92            text: result,
93            original_tokens: 0,
94            saved_tokens: 0,
95            mode: Some(action),
96            path: None,
97            changed: false,
98            shell_outcome: None,
99            content_blocks: None,
100        })
101    }
102}