use crate::checks::draft::testkit::{META, client, findings_for, post, server, trace};
fn call(seq: u64) -> Vec<String> {
vec![
post(seq, r#"{"mcp-method":"tools/call","mcp-name":"echo"}"#),
client(
seq + 1,
&format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{{"name":"echo",{META}}}}}"#
),
),
]
}
fn close(seq: u64) -> String {
format!(
r#"{{"seq":{seq},"direction":"server-to-client","transport":"streamable-http","kind":"lifecycle","event":"transport-close"}}"#
)
}
#[test]
fn only_a_client_sent_response_is_reported_on_any_binding() {
let check = "transport.client-no-responses";
let mut lines = call(0);
lines.push(client(2, r#"{"jsonrpc":"2.0","id":9,"result":{}}"#));
assert_eq!(findings_for(check, &trace(&lines)).len(), 1);
let mut lines = call(0);
lines.push(client(
2,
r#"{"jsonrpc":"2.0","id":9,"error":{"code":-32000,"message":"x"}}"#,
));
assert_eq!(findings_for(check, &trace(&lines)).len(), 1);
let mut lines = call(0);
lines.push(server(
2,
r#"{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete"}}"#,
));
assert!(findings_for(check, &trace(&lines)).is_empty());
let mut lines = call(0);
lines.push(client(2, r#"{"jsonrpc":"2.0","result":{}}"#));
assert!(findings_for(check, &trace(&lines)).is_empty());
let mut lines = call(0);
lines.push(client(
2,
r#"{"jsonrpc":"2.0","id":9,"method":"ping","result":{}}"#,
));
assert!(findings_for(check, &trace(&lines)).is_empty());
let stdio = [
r#"{"seq":0,"direction":"client-to-server","transport":"stdio","kind":"message","payload":{"jsonrpc":"2.0","id":9,"result":{}}}"#,
]
.join("\n");
assert_eq!(findings_for(check, &stdio).len(), 1);
}
#[test]
fn cancellation_binds_messages_strictly_after_the_close() {
let check = "transport.no-messages-after-cancellation";
let answer = server(
3,
r#"{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete"}}"#,
);
let mut lines = call(0);
lines.push(close(2));
lines.push(answer.clone());
let findings = findings_for(check, &trace(&lines));
assert_eq!(findings.len(), 1, "{findings:?}");
let mut lines = call(0);
lines.push(server(
2,
r#"{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete"}}"#,
));
lines.push(close(3));
assert!(findings_for(check, &trace(&lines)).is_empty());
let mut lines = call(0);
lines.push(close(2));
lines.push(client(3, r#"{"jsonrpc":"2.0","id":1,"result":{}}"#));
assert!(
findings_for(check, &trace(&lines)).is_empty(),
"the clause binds the server"
);
let mut lines = call(0);
lines.push(close(2));
lines.push(server(
3,
r#"{"jsonrpc":"2.0","id":77,"result":{"resultType":"complete"}}"#,
));
assert!(findings_for(check, &trace(&lines)).is_empty());
let mut lines = call(0);
lines.push(answer);
assert!(findings_for(check, &trace(&lines)).is_empty());
}