use serde_json::json;
use std::time::Duration;
mod mcp_test_helpers;
use mcp_test_helpers::with_mcp_test_server;
#[tokio::test]
async fn test_multiple_reinitializations_different_versions() {
with_mcp_test_server("multiple_reinit_test", |server| async move {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.cookie_store(true)
.build()?;
let versions = vec!["2025-06-18", "2025-03-26", "2025-06-18", "2025-03-26"];
for (i, version) in versions.iter().enumerate() {
let init_request = json!({
"jsonrpc": "2.0",
"id": i + 1,
"method": "initialize",
"params": {
"protocolVersion": version,
"capabilities": {},
"clientInfo": {"name": format!("test-v{}", i), "version": format!("{}.0", i)}
}
});
let response = client
.post(&server.http_url())
.json(&init_request)
.send()
.await?;
assert_eq!(response.status(), 200);
let body: serde_json::Value = response.json().await?;
assert!(body.get("result").is_some(), "Initialization {} failed", i);
let result = body.get("result").unwrap();
assert_eq!(result["protocolVersion"], *version);
let tools_request = json!({
"jsonrpc": "2.0",
"id": 100 + i,
"method": "tools/list"
});
let response = client
.post(&server.http_url())
.json(&tools_request)
.send()
.await?;
assert_eq!(response.status(), 200);
let body: serde_json::Value = response.json().await?;
assert!(body.get("result").is_some(), "Tools list failed after re-init {}", i);
}
Ok(())
})
.await
.unwrap();
}
#[tokio::test]
async fn test_reinit_with_conflicting_capabilities() {
with_mcp_test_server("reinit_capabilities_test", |server| async move {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.cookie_store(true)
.build()?;
let init1 = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {
"roots": {"listChanged": true}
},
"clientInfo": {"name": "client-basic", "version": "1.0"}
}
});
let response = client.post(&server.http_url()).json(&init1).send().await?;
assert_eq!(response.status(), 200);
let init2 = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {
"experimental": {"custom": true},
"roots": {"listChanged": false}
},
"clientInfo": {"name": "client-advanced", "version": "2.0"}
}
});
let response = client.post(&server.http_url()).json(&init2).send().await?;
assert_eq!(response.status(), 200);
let body: serde_json::Value = response.json().await?;
assert!(body.get("result").is_some());
Ok(())
})
.await
.unwrap();
}
#[tokio::test]
async fn test_session_state_isolation_after_reinit() {
with_mcp_test_server("session_state_isolation_test", |server| async move {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.cookie_store(true)
.build()?;
let init1 = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "state-test-v1", "version": "1.0"}
}
});
client.post(&server.http_url()).json(&init1).send().await?;
let tool_call = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "echo",
"arguments": {"message": "session state test"}
}
});
client.post(&server.http_url()).json(&tool_call).send().await?;
let init2 = json!({
"jsonrpc": "2.0",
"id": 3,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "state-test-v2", "version": "2.0"}
}
});
let response = client.post(&server.http_url()).json(&init2).send().await?;
assert_eq!(response.status(), 200);
let server_info = json!({
"jsonrpc": "2.0",
"id": 4,
"method": "server/get_info"
});
let response = client.post(&server.http_url()).json(&server_info).send().await?;
let body: serde_json::Value = response.json().await?;
if body.get("result").is_some() {
let result = body.get("result").unwrap();
if let Some(client_info) = result.get("clientInfo") {
assert_eq!(client_info["name"], "state-test-v2");
}
}
Ok(())
})
.await
.unwrap();
}
#[tokio::test]
async fn test_rapid_reinitializations() {
with_mcp_test_server("rapid_reinit_test", |server| async move {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.cookie_store(true)
.build()?;
for i in 0..10 {
let init = json!({
"jsonrpc": "2.0",
"id": i + 1,
"method": "initialize",
"params": {
"protocolVersion": if i % 2 == 0 { "2025-06-18" } else { "2025-03-26" },
"capabilities": {},
"clientInfo": {"name": "rapid-test", "version": format!("{}.0", i)}
}
});
let response = client.post(&server.http_url()).json(&init).send().await?;
assert_eq!(response.status(), 200);
}
let tools = json!({
"jsonrpc": "2.0",
"id": 100,
"method": "tools/list"
});
let response = client.post(&server.http_url()).json(&tools).send().await?;
assert_eq!(response.status(), 200);
let body: serde_json::Value = response.json().await?;
assert!(body.get("result").is_some());
Ok(())
})
.await
.unwrap();
}
#[tokio::test]
async fn test_reinit_invalid_protocol_fallback() {
with_mcp_test_server("invalid_protocol_reinit_test", |server| async move {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.cookie_store(true)
.build()?;
let init1 = json!({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "test", "version": "1.0"}
}
});
client.post(&server.http_url()).json(&init1).send().await?;
let init2 = json!({
"jsonrpc": "2.0",
"id": 2,
"method": "initialize",
"params": {
"protocolVersion": "2099-99-99", "capabilities": {},
"clientInfo": {"name": "test", "version": "2.0"}
}
});
let response = client.post(&server.http_url()).json(&init2).send().await?;
if response.status() == 400 {
assert!(true, "Server correctly rejected invalid version with 400");
} else if response.status() == 200 {
let body: serde_json::Value = response.json().await?;
if let Some(result) = body.get("result") {
let version = result["protocolVersion"].as_str().unwrap();
assert!(
version == "2025-06-18" || version == "2025-03-26",
"Should negotiate to supported version"
);
} else if let Some(error) = body.get("error") {
assert!(error["message"].as_str().unwrap().contains("version"));
} else {
panic!("Expected either result with negotiated version or error");
}
} else {
panic!("Unexpected status code: {}", response.status());
}
Ok(())
})
.await
.unwrap();
}