From 8a98a52624b633e6b613bb96503ed42a86f64935 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Mon, 31 Aug 2026 00:40:23 +0000 Subject: [PATCH] test(mcp): schema/batch missing-argument INVALID_INPUT arms (COV-12 review-002) schema tool with None arguments and batch tool without a calls array both return INVALID_INPUT naming the required field, without dispatching. --- src/adapters/to_mcp.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/adapters/to_mcp.rs b/src/adapters/to_mcp.rs index e9c67c3..334792b 100644 --- a/src/adapters/to_mcp.rs +++ b/src/adapters/to_mcp.rs @@ -1106,6 +1106,73 @@ mod tests { ); } + #[tokio::test] + async fn schema_tool_without_arguments_is_invalid_input() { + let registry = full_registry_with_ops(vec![( + "fs/readFile".to_string(), + OperationType::Query, + AccessControl::default(), + )]); + let gateway = ToMcpGateway::new(dispatch(registry)); + + let result = invoke_tool(&gateway, "schema", None, None).await; + assert_eq!(result.is_error, Some(true)); + let structured = result.structured_content.expect("structured error present"); + assert_eq!( + structured.get("code"), + Some(&Value::String("INVALID_INPUT".to_string())) + ); + let message = structured + .get("message") + .and_then(Value::as_str) + .expect("message"); + assert!( + message.contains("`name` is required"), + "missing tool arguments must name the required field: {message}" + ); + } + + #[tokio::test] + async fn batch_tool_without_calls_argument_is_invalid_input_without_dispatching() { + let registry = full_registry_with_ops(vec![( + "echo/run".to_string(), + OperationType::Query, + AccessControl::default(), + )]); + let gateway = ToMcpGateway::new(dispatch(registry)); + + let none_args = invoke_tool(&gateway, "batch", None, None).await; + assert_eq!(none_args.is_error, Some(true)); + let structured = none_args + .structured_content + .expect("structured error present"); + assert_eq!( + structured.get("code"), + Some(&Value::String("INVALID_INPUT".to_string())) + ); + assert_eq!(structured.get("retryable"), Some(&Value::Bool(false))); + let message = structured + .get("message") + .and_then(Value::as_str) + .expect("message"); + assert!( + message.contains("`calls` is required"), + "missing batch arguments must name the required field: {message}" + ); + + let mut args = Map::new(); + args.insert("calls".to_string(), Value::String("nope".to_string())); + let non_array = invoke_tool(&gateway, "batch", Some(args), None).await; + assert_eq!(non_array.is_error, Some(true)); + let structured = non_array + .structured_content + .expect("structured error present"); + assert_eq!( + structured.get("code"), + Some(&Value::String("INVALID_INPUT".to_string())) + ); + } + #[tokio::test] async fn call_returns_structured_error_for_call_error() { let registry = full_registry_with_ops(vec![]);