feat(sandbox): 使用逐调用截止时间驱动原生 MCP 会话

This commit is contained in:
2026-09-09 00:49:14 +08:00
parent 12bcc8b1fa
commit 7c7a637e38
6 changed files with 553 additions and 5 deletions
@@ -3,6 +3,42 @@ use std::net::{SocketAddr, TcpStream, UdpSocket};
use std::time::Duration;
fn main() {
let args: Vec<_> = std::env::args().collect();
if args.get(1).is_some_and(|s| s.starts_with("mcp")) {
use std::io::{BufRead, Write};
fn read(reader: &mut impl BufRead) -> String { let mut line = String::new(); reader.read_line(&mut line).unwrap(); line }
fn id(line: &str) -> &str { line.split("\"id\":\"").nth(1).unwrap().split('"').next().unwrap() }
fn reply(id: &str, result: &str) { println!("{{\"jsonrpc\":\"2.0\",\"id\":\"{id}\",\"result\":{result}}}"); std::io::stdout().flush().unwrap(); }
let mut input = std::io::stdin().lock();
let request = read(&mut input);
assert!(request.contains("\"method\":\"initialize\""));
reply(id(&request), if args[1] == "mcp_bad_version" { r#"{"protocolVersion":"unknown","capabilities":{},"serverInfo":{"name":"fixture","version":"1"}}"# } else { r#"{"protocolVersion":"2025-11-25","capabilities":{"tools":{}},"serverInfo":{"name":"fixture","version":"1"}}"# });
assert!(read(&mut input).contains("notifications/initialized"));
let request = read(&mut input);
assert!(request.contains("tools/list"));
reply(id(&request), r#"{"tools":[{"name":"echo","inputSchema":{"type":"object"}}]}"#);
let mut request = read(&mut input);
assert!(request.contains("tools/call"));
if args[1] == "mcp_cancel" || args[1] == "mcp_deadline" {
let _child = std::process::Command::new(std::env::current_exe().unwrap()).arg("wait").spawn().unwrap();
std::thread::sleep(Duration::from_secs(120));
return;
}
if args[1] == "mcp_remote_error" {
println!("{{\"jsonrpc\":\"2.0\",\"id\":\"{}\",\"error\":{{\"code\":-32602,\"message\":\"fixture error\"}}}}", id(&request));
std::io::stdout().flush().unwrap();
request = read(&mut input);
assert!(request.contains("tools/call"));
}
println!(r#"{{"jsonrpc":"2.0","id":"server-ping","method":"ping"}}"#);
std::io::stdout().flush().unwrap();
let ping = read(&mut input);
assert!(ping.contains("server-ping") && ping.contains("result"));
println!(r#"{{"jsonrpc":"2.0","method":"notifications/tools/list_changed"}}"#);
reply(if args[1] == "mcp_wrong_id" { "wrong-request" } else { id(&request) }, r#"{"content":[{"type":"text","text":"native MCP success"}]}"#);
// MCP server remains alive between calls until Host closes stdin.
while !read(&mut input).is_empty() {}
return;
}
if args.get(1).is_some_and(|s| s == "stderr_flood" || s == "stdout_flood") {
use std::io::Write;
let _child = std::process::Command::new(std::env::current_exe().unwrap()).arg("wait").spawn().unwrap();