use mcpkit::protocol::{Message, Notification, Request, RequestId, Response};
use mcpkit_transport::{MemoryTransport, Transport};
use serde_json::json;
#[tokio::test]
async fn test_memory_transport_basic() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
assert!(client.is_connected());
assert!(server.is_connected());
let request = Request::new("tools/list", 1u64);
client.send(Message::Request(request)).await?;
let received = server.recv().await?.ok_or("Expected message from server")?;
assert!(matches!(received, Message::Request(_)));
let response = Response::success(1u64, json!({"tools": []}));
server.send(Message::Response(response)).await?;
let received = client.recv().await?.ok_or("Expected message from client")?;
assert!(matches!(received, Message::Response(_)));
Ok(())
}
#[tokio::test]
async fn test_request_response_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
let init_request = Request::with_params(
"initialize",
1u64,
json!({
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}),
);
client.send(Message::Request(init_request)).await?;
let msg = server.recv().await?.ok_or("Expected message from server")?;
let request = msg.as_request().ok_or("Expected request message")?;
assert_eq!(request.method, "initialize");
assert_eq!(request.id, RequestId::Number(1));
let init_response = Response::success(
1u64,
json!({
"protocolVersion": "2025-11-25",
"capabilities": {"tools": {}},
"serverInfo": {
"name": "test-server",
"version": "1.0.0"
}
}),
);
server.send(Message::Response(init_response)).await?;
let msg = client.recv().await?.ok_or("Expected message from client")?;
let response = msg.as_response().ok_or("Expected response message")?;
assert!(response.is_success());
let result = response
.result
.as_ref()
.ok_or("Expected result in response")?;
assert_eq!(result["protocolVersion"], "2025-11-25");
assert_eq!(result["serverInfo"]["name"], "test-server");
Ok(())
}
#[tokio::test]
async fn test_notification_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
let notification = Notification::new("notifications/initialized");
client.send(Message::Notification(notification)).await?;
let msg = server.recv().await?.ok_or("Expected message from server")?;
let notification = msg
.as_notification()
.ok_or("Expected notification message")?;
assert_eq!(notification.method, "notifications/initialized");
assert!(msg.id().is_none()); Ok(())
}
#[tokio::test]
async fn test_message_sequence() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
for i in 1..=5 {
let request = Request::new("ping", i as u64);
client.send(Message::Request(request)).await?;
}
for i in 1..=5 {
let msg = server.recv().await?.ok_or("Expected message from server")?;
let request = msg.as_request().ok_or("Expected request message")?;
assert_eq!(request.id, RequestId::Number(i));
let response = Response::success(i, json!({"pong": i}));
server.send(Message::Response(response)).await?;
}
for i in 1..=5 {
let msg = client.recv().await?.ok_or("Expected message from client")?;
let response = msg.as_response().ok_or("Expected response message")?;
assert_eq!(response.id, RequestId::Number(i));
assert_eq!(
response
.result
.as_ref()
.ok_or("Expected result")?
.get("pong")
.ok_or("Expected pong field")?,
i
);
}
Ok(())
}
#[tokio::test]
async fn test_transport_disconnect() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
assert!(client.is_connected());
assert!(server.is_connected());
client.close().await?;
assert!(!client.is_connected());
assert!(!server.is_connected());
Ok(())
}
#[tokio::test]
async fn test_error_response() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
let request = Request::new("unknown/method", 1u64);
client.send(Message::Request(request)).await?;
let _ = server.recv().await?.ok_or("Expected message from server")?;
let error = mcpkit::error::JsonRpcError::method_not_found("Method unknown/method not found");
let response = Response::error(1u64, error);
server.send(Message::Response(response)).await?;
let msg = client.recv().await?.ok_or("Expected message from client")?;
let response = msg.as_response().ok_or("Expected response message")?;
assert!(response.is_error());
assert_eq!(
response
.error
.as_ref()
.ok_or("Expected error in response")?
.code,
-32601
);
Ok(())
}
#[tokio::test]
async fn test_tool_call_lifecycle() -> Result<(), Box<dyn std::error::Error>> {
let (client, server) = MemoryTransport::pair();
let init_request = Request::with_params(
"initialize",
1u64,
json!({
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {"name": "test", "version": "1.0"}
}),
);
client.send(Message::Request(init_request)).await?;
let _ = server.recv().await?;
let init_response = Response::success(
1u64,
json!({
"protocolVersion": "2025-11-25",
"capabilities": {"tools": {}},
"serverInfo": {"name": "test-server", "version": "1.0"}
}),
);
server.send(Message::Response(init_response)).await?;
let _ = client.recv().await?;
let initialized = Notification::new("notifications/initialized");
client.send(Message::Notification(initialized)).await?;
let _ = server.recv().await?;
let list_tools = Request::new("tools/list", 2u64);
client.send(Message::Request(list_tools)).await?;
let _ = server.recv().await?;
let tools_response = Response::success(
2u64,
json!({
"tools": [{
"name": "echo",
"description": "Echo back the input",
"inputSchema": {
"type": "object",
"properties": {
"message": {"type": "string"}
}
}
}]
}),
);
server.send(Message::Response(tools_response)).await?;
let msg = client.recv().await?.ok_or("Expected message from client")?;
let response = msg.as_response().ok_or("Expected response message")?;
let tools = response
.result
.as_ref()
.ok_or("Expected result")?
.get("tools")
.ok_or("Expected tools field")?
.as_array()
.ok_or("Expected tools array")?;
assert_eq!(tools.len(), 1);
assert_eq!(tools[0]["name"], "echo");
let call_tool = Request::with_params(
"tools/call",
3u64,
json!({
"name": "echo",
"arguments": {"message": "Hello, MCP!"}
}),
);
client.send(Message::Request(call_tool)).await?;
let msg = server.recv().await?.ok_or("Expected message from server")?;
let request = msg.as_request().ok_or("Expected request message")?;
assert_eq!(request.method, "tools/call");
let call_response = Response::success(
3u64,
json!({
"content": [{"type": "text", "text": "Hello, MCP!"}],
"isError": false
}),
);
server.send(Message::Response(call_response)).await?;
let msg = client.recv().await?.ok_or("Expected message from client")?;
let response = msg.as_response().ok_or("Expected response message")?;
assert!(response.is_success());
let result = response.result.as_ref().ok_or("Expected result")?;
assert_eq!(result["content"][0]["text"], "Hello, MCP!");
Ok(())
}
#[tokio::test]
async fn test_wire_format() -> Result<(), Box<dyn std::error::Error>> {
let request = Request::new("test/method", 1u64);
let json = serde_json::to_value(&request)?;
assert_eq!(json["jsonrpc"], "2.0");
assert_eq!(json["method"], "test/method");
assert_eq!(json["id"], 1);
let response = Response::success(1u64, json!({"result": "value"}));
let json = serde_json::to_value(&response)?;
assert_eq!(json["jsonrpc"], "2.0");
assert_eq!(json["id"], 1);
assert!(json["result"].is_object());
assert!(json.get("error").is_none());
let notification = Notification::new("notifications/test");
let json = serde_json::to_value(¬ification)?;
assert_eq!(json["jsonrpc"], "2.0");
assert_eq!(json["method"], "notifications/test");
assert!(json.get("id").is_none());
Ok(())
}
#[tokio::test]
async fn test_wire_format_parsing() -> Result<(), Box<dyn std::error::Error>> {
let request_json = json!({
"jsonrpc": "2.0",
"id": 42,
"method": "test/method",
"params": {"key": "value"}
});
let msg: Message = serde_json::from_value(request_json)?;
assert!(msg.is_request());
assert_eq!(msg.method(), Some("test/method"));
assert_eq!(msg.id(), Some(&RequestId::Number(42)));
let response_json = json!({
"jsonrpc": "2.0",
"id": 42,
"result": {"data": "test"}
});
let msg: Message = serde_json::from_value(response_json)?;
assert!(msg.is_response());
let notification_json = json!({
"jsonrpc": "2.0",
"method": "notifications/test"
});
let msg: Message = serde_json::from_value(notification_json)?;
assert!(msg.is_notification());
assert!(msg.id().is_none());
Ok(())
}