browser-control 0.2.1

CLI that manages browsers and exposes them over CDP/BiDi for agent-driven development. Includes an optional MCP server.
Documentation
use browser_control::cli::env_resolver::{ResolvedBrowser, Source};
use browser_control::detect::Engine;
use browser_control::mcp::playwright::run_with_streams;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

fn dummy_resolved() -> ResolvedBrowser {
    ResolvedBrowser {
        endpoint: "ws://127.0.0.1:9999/fake".into(),
        engine: Engine::Cdp,
        source: Source::External,
    }
}

#[tokio::test]
async fn stdio_passthrough_round_trips() {
    if which::which("node").is_err() {
        eprintln!("node not installed, skipping");
        return;
    }
    let script = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests/fixtures/fake_playwright_mcp.js");

    let (mut c_in_w, c_in_r) = tokio::io::duplex(8192);
    let (c_out_w, mut c_out_r) = tokio::io::duplex(8192);
    let (c_err_w, mut c_err_r) = tokio::io::duplex(8192);

    let browser = dummy_resolved();
    let cmd = (
        "node".to_string(),
        vec![
            script.to_string_lossy().to_string(),
            "--cdp-endpoint".into(),
            browser.endpoint.clone(),
        ],
    );

    let handle = tokio::spawn(async move {
        run_with_streams(&browser, c_in_r, c_out_w, c_err_w, Some(cmd))
            .await
            .unwrap()
    });

    let req = b"{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"ping\"}\n";
    c_in_w.write_all(req).await.unwrap();
    drop(c_in_w);

    let mut buf = Vec::new();
    c_out_r.read_to_end(&mut buf).await.unwrap();
    let s = String::from_utf8(buf).unwrap();
    assert!(s.contains("\"id\":1"), "expected echo of id=1, got: {s}");
    assert!(s.contains("\"echo\""));

    let mut ebuf = Vec::new();
    c_err_r.read_to_end(&mut ebuf).await.unwrap();
    let e = String::from_utf8(ebuf).unwrap();
    assert!(
        e.contains("fake-playwright-mcp: started"),
        "stderr was: {e}"
    );

    let code = handle.await.unwrap();
    assert_eq!(code, 0);
}