use super::mcp_call_tool_result_output_schema; use super::parse_agent_plugin_mcp_tool; use super::parse_mcp_tool; use crate::JsonSchema; use crate::ToolDefinition; use pretty_assertions::assert_eq; use std::collections::BTreeMap; fn mcp_tool(name: &str, description: &str, input_schema: serde_json::Value) -> rmcp::model::Tool { rmcp::model::Tool::new( name.to_string(), description.to_string(), std::sync::Arc::new(rmcp::model::object(input_schema)), ) } #[test] fn parse_mcp_tool_inserts_empty_properties() { let tool = mcp_tool( "no_props", "No properties", serde_json::json!({ "type": "object" }), ); assert_eq!( parse_mcp_tool(&tool).expect("parse MCP tool"), ToolDefinition { name: "no_props".to_string(), description: "No properties".to_string(), input_schema: JsonSchema::object( BTreeMap::new(), /*required*/ None, /*additional_properties*/ None ), output_schema: Some(mcp_call_tool_result_output_schema(serde_json::json!({}))), defer_loading: false, } ); } #[test] fn agent_plugin_mcp_tool_bounds_model_visible_description() { let description = format!("{}é", "a".repeat(super::MAX_MCP_TOOL_DESCRIPTION_BYTES - 1)); let tool = mcp_tool( "bounded_description", &description, serde_json::json!({"type": "object"}), ); let parsed = parse_agent_plugin_mcp_tool(&tool).expect("parse Agent Plugin MCP tool"); assert_eq!( parsed.description.len(), super::MAX_MCP_TOOL_DESCRIPTION_BYTES - 1 ); } #[test] fn legacy_mcp_tool_preserves_long_description() { let description = "a".repeat(super::MAX_MCP_TOOL_DESCRIPTION_BYTES + 100); let tool = mcp_tool( "legacy_description", &description, serde_json::json!({"type": "object"}), ); assert_eq!( parse_mcp_tool(&tool) .expect("parse legacy MCP tool") .description, description ); } #[test] fn parse_mcp_tool_preserves_top_level_output_schema() { let mut tool = mcp_tool( "with_output", "Has output schema", serde_json::json!({ "type": "object" }), ); tool.output_schema = Some(std::sync::Arc::new(rmcp::model::object( serde_json::json!({ "properties": { "result": { "properties": { "nested": {} } } }, "required": ["result"] }), ))); assert_eq!( parse_mcp_tool(&tool).expect("parse MCP tool"), ToolDefinition { name: "with_output".to_string(), description: "Has output schema".to_string(), input_schema: JsonSchema::object( BTreeMap::new(), /*required*/ None, /*additional_properties*/ None ), output_schema: Some(mcp_call_tool_result_output_schema(serde_json::json!({ "properties": { "result": { "properties": { "nested": {} } } }, "required": ["result"] }))), defer_loading: false, } ); } #[test] fn parse_mcp_tool_preserves_output_schema_without_inferred_type() { let mut tool = mcp_tool( "with_enum_output", "Has enum output schema", serde_json::json!({ "type": "object" }), ); tool.output_schema = Some(std::sync::Arc::new(rmcp::model::object( serde_json::json!({ "enum": ["ok", "error"] }), ))); assert_eq!( parse_mcp_tool(&tool).expect("parse MCP tool"), ToolDefinition { name: "with_enum_output".to_string(), description: "Has enum output schema".to_string(), input_schema: JsonSchema::object( BTreeMap::new(), /*required*/ None, /*additional_properties*/ None ), output_schema: Some(mcp_call_tool_result_output_schema(serde_json::json!({ "enum": ["ok", "error"] }))), defer_loading: false, } ); }