use serde_json::json;
#[test]
fn test_tools_list_request_structure() {
let request = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"group": "test-group"
}
});
assert_eq!(request["jsonrpc"], "2.0", "jsonrpc version must be 2.0");
assert!(request["id"].is_number(), "id must be present");
assert_eq!(request["method"], "tools/list", "method must be tools/list");
assert_eq!(
request["params"]["group"], "test-group",
"group parameter required"
);
}
#[test]
fn test_tools_list_response_format() {
let response = json!({
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "example_tool",
"description": "An example tool for testing",
"inputSchema": {
"type": "object",
"properties": {
"arg1": {
"type": "string",
"description": "First argument"
}
},
"required": ["arg1"]
}
}
]
}
});
assert_eq!(response["jsonrpc"], "2.0");
assert!(response["id"].is_number());
assert!(
response["result"]["tools"].is_array(),
"tools must be array"
);
let tools = &response["result"]["tools"];
assert!(tools.is_array());
if let Some(tool) = tools.get(0) {
assert!(tool["name"].is_string(), "tool name is required");
assert!(
tool["description"].is_string(),
"tool description should be present"
);
assert!(tool["inputSchema"].is_object(), "inputSchema is required");
let schema = &tool["inputSchema"];
assert!(schema["type"].is_string(), "inputSchema.type is required");
assert!(schema["properties"].is_object() || schema["properties"].is_null());
}
}
#[test]
fn test_tools_input_schema_types() {
let tools_with_schemas = vec![
json!({
"name": "string_tool",
"inputSchema": {
"type": "object",
"properties": {
"text": {"type": "string"}
},
"required": ["text"]
}
}),
json!({
"name": "multi_param_tool",
"inputSchema": {
"type": "object",
"properties": {
"name": {"type": "string"},
"count": {"type": "number"},
"active": {"type": "boolean"}
},
"required": ["name"]
}
}),
json!({
"name": "optional_params_tool",
"inputSchema": {
"type": "object",
"properties": {
"required_param": {"type": "string"},
"optional_param": {"type": "string"}
},
"required": ["required_param"]
}
}),
json!({
"name": "nested_schema_tool",
"inputSchema": {
"type": "object",
"properties": {
"config": {
"type": "object",
"properties": {
"timeout": {"type": "number"},
"retries": {"type": "integer"}
}
}
}
}
}),
];
for tool in tools_with_schemas {
assert!(tool["name"].is_string());
assert!(tool["inputSchema"]["type"].is_string());
assert!(
tool["inputSchema"]["properties"].is_object()
|| tool["inputSchema"]["type"] == "object"
);
}
}
#[test]
fn test_tools_call_request_format() {
let request = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"group": "test-group",
"name": "example_tool",
"arguments": {
"arg1": "value1",
"arg2": 42
}
}
});
assert_eq!(request["method"], "tools/call");
assert!(request["params"]["group"].is_string());
assert!(request["params"]["name"].is_string());
assert!(
request["params"]["arguments"].is_object(),
"arguments must be object"
);
}
#[test]
fn test_tools_call_success_response() {
let response = json!({
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Tool execution successful"
}
]
}
});
assert!(response["result"]["content"].is_array());
let content = &response["result"]["content"][0];
assert!(content["type"].is_string());
assert!(content["text"].is_string());
}
#[test]
fn test_tools_call_error_response_format() {
let error_response = json!({
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Error: Invalid input parameter",
"isError": true
}
]
}
});
assert!(error_response["result"]["content"].is_array());
let content = &error_response["result"]["content"][0];
assert_eq!(content["type"], "text");
assert_eq!(
content["isError"], true,
"isError flag must be true for errors"
);
assert!(content["text"].is_string());
}
#[test]
fn test_tools_multiple_content_types() {
let multi_content = json!({
"content": [
{
"type": "text",
"text": "Processing complete"
},
{
"type": "image",
"data": "base64encodedimage",
"mimeType": "image/png"
},
{
"type": "resource",
"resource": {
"uri": "file:///output.json",
"mimeType": "application/json"
}
}
]
});
assert!(multi_content["content"].is_array());
let content_array = multi_content["content"].as_array().unwrap();
assert_eq!(content_array[0]["type"], "text");
assert!(content_array[0]["text"].is_string());
assert_eq!(content_array[1]["type"], "image");
assert!(content_array[1]["data"].is_string());
assert!(content_array[1]["mimeType"].is_string());
assert_eq!(content_array[2]["type"], "resource");
assert!(content_array[2]["resource"]["uri"].is_string());
}
#[test]
fn test_tools_list_pagination() {
let paginated_response = json!({
"tools": [
{
"name": "tool1",
"inputSchema": {"type": "object"}
},
{
"name": "tool2",
"inputSchema": {"type": "object"}
}
],
"nextCursor": "cursor_for_next_page"
});
assert!(paginated_response["tools"].is_array());
assert!(paginated_response["nextCursor"].is_string());
}
#[test]
fn test_tools_capability_declaration() {
let initialize_response = json!({
"capabilities": {
"tools": {},
"resources": {
"subscribe": true
},
"prompts": {}
}
});
assert!(
initialize_response["capabilities"]["tools"].is_object(),
"tools capability must be present"
);
}
#[test]
fn test_tools_api_error_codes() {
let errors = vec![
(
-32601,
json!({
"code": -32601,
"message": "Method not found: invalid_method",
"data": null
}),
),
(
-32602,
json!({
"code": -32602,
"message": "Invalid params: missing required group",
"data": null
}),
),
(
-32603,
json!({
"code": -32603,
"message": "Internal error: failed to list tools",
"data": null
}),
),
];
for (expected_code, error) in errors {
assert_eq!(error["code"], expected_code);
assert!(error["message"].is_string());
}
}
#[test]
fn test_tools_with_no_parameters() {
let tool = json!({
"name": "no_params_tool",
"description": "Tool that takes no parameters",
"inputSchema": {
"type": "object",
"properties": {},
"required": []
}
});
assert!(tool["inputSchema"]["properties"].is_object());
assert!(tool["inputSchema"]["required"].is_array());
assert_eq!(tool["inputSchema"]["required"].as_array().unwrap().len(), 0);
}
#[test]
fn test_config_tools_config() {
let config = json!({
"mcpServers": {
"test-group": {
"description": "Server with comprehensive tools, resources, and prompts",
"command": "npx",
"args": ["-y", "test-server"]
}
}
});
let server_config = &config["mcpServers"]["test-group"];
assert!(server_config["description"].is_string());
assert_eq!(server_config["command"], "npx");
assert!(server_config["args"].is_array());
}
#[test]
fn test_tools_call_complex_arguments() {
let request = json!({
"method": "tools/call",
"params": {
"group": "test-group",
"name": "complex_tool",
"arguments": {
"simple": "string",
"number": 42,
"boolean": true,
"null_value": null,
"array": [1, 2, 3],
"object": {
"nested": "value",
"count": 100
},
"special_chars": "test!@#$%^&*()_+-=[]{}|;':\",./<>?"
}
}
});
let args = &request["params"]["arguments"];
assert!(args["simple"].is_string());
assert!(args["number"].is_number());
assert!(args["boolean"].is_boolean());
assert!(args["null_value"].is_null());
assert!(args["array"].is_array());
assert!(args["object"].is_object());
assert!(args["special_chars"].is_string());
}
#[test]
fn test_tools_list_empty_response() {
let empty_response = json!({
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": []
}
});
assert!(empty_response["result"]["tools"].is_array());
assert_eq!(
empty_response["result"]["tools"].as_array().unwrap().len(),
0
);
}
#[test]
fn test_tool_input_schema_special_patterns() {
let tool_with_enum = json!({
"name": "enum_tool",
"inputSchema": {
"type": "object",
"properties": {
"format": {
"type": "string",
"enum": ["json", "xml", "csv"]
}
}
}
});
let tool_with_pattern = json!({
"name": "pattern_tool",
"inputSchema": {
"type": "object",
"properties": {
"email": {
"type": "string",
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
}
}
}
});
let tool_with_number_constraints = json!({
"name": "number_tool",
"inputSchema": {
"type": "object",
"properties": {
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
}
}
});
assert!(tool_with_enum["inputSchema"]["properties"]["format"]["enum"].is_array());
assert!(tool_with_pattern["inputSchema"]["properties"]["email"]["pattern"].is_string());
assert!(
tool_with_number_constraints["inputSchema"]["properties"]["port"]["minimum"].is_number()
);
}