Skip to main content

browser_control/cli/
mcp.rs

1//! `browser-control mcp` subcommand entry point.
2
3use anyhow::{anyhow, Result};
4
5use crate::cli::env_resolver::{self, ResolvedBrowser, Source};
6use crate::mcp::server::{run, ServerState, ToolRegistry};
7use crate::registry::Registry;
8
9/// Entry point for `browser-control mcp`.
10pub async fn run_cli(browser_arg: Option<String>, playwright: bool) -> Result<()> {
11    if playwright {
12        let resolved = resolve_browser(browser_arg).await?;
13        let code = crate::mcp::playwright::run(&resolved).await?;
14        std::process::exit(code);
15    }
16    let resolved = resolve_browser(browser_arg).await?;
17    let state = ServerState::new(resolved);
18    let tools = ToolRegistry::new();
19    crate::mcp::tools::register_all(&tools);
20    run(state, tools).await
21}
22
23/// Resolution order: positional arg / `BROWSER_CONTROL` env (arg wins, env is
24/// the fallback — both are merged by clap into `browser_arg`) > persisted
25/// default (`browser-control set default ...`) > most-recent-alive > error.
26pub async fn resolve_browser(browser_arg: Option<String>) -> Result<ResolvedBrowser> {
27    let registry = Registry::open()?;
28    if let Some(arg) = browser_arg.as_deref().filter(|s| !s.is_empty()) {
29        let sel = env_resolver::parse(arg)?;
30        return env_resolver::resolve(sel, &registry).await;
31    }
32    if let Some(value) = crate::config::load()?.default {
33        let sel = env_resolver::parse(&value)?;
34        return env_resolver::resolve(sel, &registry).await;
35    }
36    if let Some(row) = registry.most_recent_alive()? {
37        return Ok(ResolvedBrowser {
38            endpoint: row.endpoint,
39            engine: row.engine,
40            source: Source::Registered { name: row.name },
41        });
42    }
43    Err(anyhow!(
44        "no browser selected: pass a browser argument, set BROWSER_CONTROL, run `browser-control set default <value>`, or run `browser-control start`"
45    ))
46}