diff --git a/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs b/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs index db94fda65..d952268e7 100644 --- a/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs +++ b/crates/openpencil-shell-core/src/mcp/replace_node_tests.rs @@ -216,12 +216,14 @@ fn replace_node_rejects_malformed_drop_children() { args.insert("y".into(), "0".into()); args.insert("width".into(), "10".into()); args.insert("height".into(), "10".into()); - args.insert("drop_children".into(), "yes".into()); // not "true"/"false" - match tool.call(&args) { - ToolOutcome::Err(code, msg) => { - assert_eq!(code, ToolErrorCode::InvalidArgument); - assert!(msg.contains("drop_children")); + for bad in ["yes", "", "TRUE", "1", "0"] { + args.insert("drop_children".into(), bad.into()); + match tool.call(&args) { + ToolOutcome::Err(code, msg) => { + assert_eq!(code, ToolErrorCode::InvalidArgument, "input {bad:?}"); + assert!(msg.contains("drop_children"), "input {bad:?} msg = {msg}"); + } + _ => panic!("expected InvalidArgument on malformed drop_children {bad:?}"), } - _ => panic!("expected InvalidArgument on malformed drop_children"), } } diff --git a/crates/openpencil-shell-core/src/mcp/write_tools.rs b/crates/openpencil-shell-core/src/mcp/write_tools.rs index 2772b97b4..fe3f29664 100644 --- a/crates/openpencil-shell-core/src/mcp/write_tools.rs +++ b/crates/openpencil-shell-core/src/mcp/write_tools.rs @@ -609,12 +609,14 @@ impl McpTool for ReplaceNode { }; // Optional opt-in for destructive swaps. The applier // refuses to drop a container's children unless this is - // `"true"`. Any other value (including "false" / "1" / - // missing) leaves the guard active. + // `"true"`. Missing → safe default false. Any other + // value (including the empty string) is malformed and + // rejected — silently treating "" as false would hide a + // mis-serialized confirmation from the caller. let drop_children = match args.get("drop_children") { - Some(s) if s == "true" => true, - Some(s) if s == "false" || s.is_empty() => false, None => false, + Some(s) if s == "true" => true, + Some(s) if s == "false" => false, Some(s) => { return ToolOutcome::Err( ToolErrorCode::InvalidArgument,