chromewright 0.2.3

Browser automation MCP server and Rust library via Chrome DevTools Protocol (CDP)
Documentation
use crate::error::Result;
use crate::tools::{Tool, ToolContext, ToolResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

/// Parameters for the close_tab tool (no parameters needed)
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct CloseTabParams {}

/// Tool for closing the current active tab
#[derive(Default)]
pub struct CloseTabTool;

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct CloseTabOutput {
    pub index: usize,
    pub title: String,
    pub url: String,
    pub message: String,
}

impl Tool for CloseTabTool {
    type Params = CloseTabParams;
    type Output = CloseTabOutput;

    fn name(&self) -> &str {
        "close_tab"
    }

    fn execute_typed(
        &self,
        _params: CloseTabParams,
        context: &mut ToolContext,
    ) -> Result<ToolResult> {
        // Get the current tab info before closing
        let active_tab = context.session.tab()?;
        let tab_title = active_tab.get_title().unwrap_or_default();
        let tab_url = active_tab.get_url();

        // Get the current tab index
        let tabs = context.session.get_tabs()?;
        let current_index = tabs
            .iter()
            .position(|tab| std::sync::Arc::ptr_eq(tab, &active_tab))
            .unwrap_or(0);

        // Close the active tab
        context.session.clear_active_tab_hint()?;
        active_tab.close(true).map_err(|e| {
            crate::error::BrowserError::TabOperationFailed(format!("Failed to close tab: {}", e))
        })?;

        let message = close_tab_message(current_index, &tab_title, &tab_url);

        Ok(ToolResult::success_with(CloseTabOutput {
            index: current_index,
            message,
            title: tab_title,
            url: tab_url,
        }))
    }
}

fn close_tab_message(index: usize, title: &str, url: &str) -> String {
    format!("Closed tab [{}]: {} ({})", index, title, url)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_close_tab_message_includes_index_title_and_url() {
        assert_eq!(
            close_tab_message(3, "Docs", "https://example.com"),
            "Closed tab [3]: Docs (https://example.com)"
        );
    }
}