6 Commits

6 changed files with 30 additions and 17 deletions

4
Cargo.lock generated
View File

@@ -1536,8 +1536,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "todo"
version = "0.1.0"
name = "todo-mcp"
version = "0.2.1"
dependencies = [
"anyhow",
"chrono",

View File

@@ -1,6 +1,6 @@
[package]
name = "todo"
version = "0.1.0"
name = "todo-mcp"
version = "0.2.1"
edition = "2024"
rust-version = "1.85"
description = "simple todo cli with mcp server for ai integration"

View File

@@ -19,7 +19,7 @@ fn main() -> Result<(), Error> {
let mut cmd = Cli::command();
for shell in Shell::value_variants() {
let path = generate_to(*shell, &mut cmd, "todo", &outdir)?;
let path = generate_to(*shell, &mut cmd, env!("CARGO_PKG_NAME"), &outdir)?;
println!("cargo:warning=completion file is generated: {path:?}");
}

View File

@@ -86,8 +86,9 @@ pub struct ListArgs {
#[derive(Args)]
pub struct DoneArgs {
/// todo id
pub id: i64,
/// todo id(s)
#[arg(required = true)]
pub id: Vec<i64>,
}
#[derive(Args)]

View File

@@ -65,9 +65,11 @@ async fn list(ctx: &Ctx<'_>, args: ListArgs) -> Result<()> {
}
async fn done(ctx: &Ctx<'_>, args: DoneArgs) -> Result<()> {
let todo = db::complete_todo(ctx.pool, args.id).await?;
for id in args.id {
let todo = db::complete_todo(ctx.pool, id).await?;
print!("{} ", "done:".green().bold());
print_todo(&todo);
}
Ok(())
}

View File

@@ -79,9 +79,9 @@ fn tool_schemas() -> Value {
"inputSchema": {
"type": "object",
"properties": {
"id": { "type": "integer" }
},
"required": ["id"]
"id": { "type": "integer", "description": "single todo id" },
"ids": { "type": "array", "items": { "type": "integer" }, "description": "multiple todo ids" }
}
}
},
{
@@ -182,11 +182,21 @@ async fn dispatch(pool: &Pool, name: &str, args: &Value) -> Value {
.map(|t| serde_json::to_string(&t).unwrap())
}
"todo_done" => {
let id = match args.get("id").and_then(|v| v.as_i64()) {
Some(id) => id,
None => return tool_error("missing required arg: id".into()),
let ids: Vec<i64> = if let Some(arr) = args.get("ids").and_then(|v| v.as_array()) {
arr.iter().filter_map(|v| v.as_i64()).collect()
} else if let Some(id) = args.get("id").and_then(|v| v.as_i64()) {
vec![id]
} else {
return tool_error("missing required arg: id or ids".into());
};
db::complete_todo(pool, id).await.map(|t| serde_json::to_string(&t).unwrap())
let mut todos = Vec::new();
for id in ids {
match db::complete_todo(pool, id).await {
Ok(t) => todos.push(t),
Err(e) => return tool_error(e.to_string()),
}
}
Ok(serde_json::to_string(&todos).unwrap())
}
"todo_edit" => {
let id = match args.get("id").and_then(|v| v.as_i64()) {