From 7f23d59afcb762710e14b5f91b9796f9813f6ed7 Mon Sep 17 00:00:00 2001 From: Sam & Claude Date: Sat, 27 Jun 2026 13:54:50 +0200 Subject: [PATCH] feat(mcp): add colibri_list_task_costs tool + test assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dashboard-ready: agents list all tasks with cost data (tokens, cost_usd, cache ratio) filtered by optional status. Complements colibri_get_task (single task detail). Tool count: 11→12. --- crates/colibri-mcp/src/lib.rs | 20 ++++++++++++++++++++ crates/colibri-mcp/tests/tool_dispatch.rs | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/colibri-mcp/src/lib.rs b/crates/colibri-mcp/src/lib.rs index 0225b1c..e9071ca 100644 --- a/crates/colibri-mcp/src/lib.rs +++ b/crates/colibri-mcp/src/lib.rs @@ -15,6 +15,8 @@ //! | `colibri_create_task` | write-gated| Create a task | //! | `colibri_intake_task` | write-gated| Submit intake task with capabilities| //! | `colibri_set_cost_mode` | write-gated | Switch cost mode (fast/smart/max) | +//! | `colibri_get_task` | read-only | Task details with cost data | +//! | `colibri_list_task_costs` | read-only | All tasks with cost (dashboard) | //! //! Write tools require `COLIBRI_MCP_WRITE=1`. @@ -156,6 +158,16 @@ pub fn tool_list() -> Vec { "required": ["task_id"] })), ), + json_tool( + "colibri_list_task_costs", + "List all tasks with cost data (tokens, cost_usd, cache ratio, success). Dashboard-ready summary for web UI.", + Some(serde_json::json!({ + "type": "object", + "properties": { + "status": { "type": "string", "description": "Optional status filter: done, failed, or empty for all" } + } + })), + ), json_tool( "colibri_external_mcp_servers", "List configured external MCP servers from COLIBRI_MCP_EXTERNAL_CONFIG", @@ -304,6 +316,14 @@ pub async fn dispatch_tool( None => Err(McpError::not_found(format!("task not found: {task_id}"))), } } + "colibri_list_task_costs" => { + let status = arguments + .get("status") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + let all_tasks = client.list_tasks(status.as_deref()).await.map_err(map_client_error)?; + Ok(tool_text(all_tasks)) + } "colibri_external_mcp_servers" => { let registry = external::load_registry_if_present(&config.external_config_path).await?; Ok(tool_text(serde_json::json!({ diff --git a/crates/colibri-mcp/tests/tool_dispatch.rs b/crates/colibri-mcp/tests/tool_dispatch.rs index f5119a4..c505c43 100644 --- a/crates/colibri-mcp/tests/tool_dispatch.rs +++ b/crates/colibri-mcp/tests/tool_dispatch.rs @@ -252,6 +252,8 @@ fn tool_list_has_all_phase1_tools() { assert!(names.contains(&"colibri_external_mcp_servers")); assert!(names.contains(&"colibri_external_mcp_list_tools")); assert!(names.contains(&"colibri_external_mcp_call_tool")); + assert!(names.contains(&"colibri_list_task_costs")); + assert!(names.contains(&"colibri_get_task")); - assert_eq!(names.len(), 11); + assert_eq!(names.len(), 12); }