Default MCP tab tools to the active tab
Testing / remote-protocol-compat (0.15.0) (push) Successful in 30s
Testing / test (push) Successful in 40s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 24s

Requiring an explicit tab_id forced every navigate or close through a
preceding tabs_list call, which costs an MCP client a full round trip just to
learn the ID the browser already considers current.

navigate and tabs_close now resolve the active tab when tab_id is omitted,
matching the screenshot tool. Resolution is explicit rather than forwarding
None into the SDK, so the acting tool knows which tab it touched; tabs_close
reports it, since closing the wrong tab is not recoverable.

This stays in the MCP layer: the SDK and CLI signatures are unchanged.
This commit is contained in:
2026-08-09 20:41:41 +02:00
parent bd2a18baba
commit 581cd73cac
4 changed files with 49 additions and 8 deletions
+11 -8
View File
@@ -16,6 +16,7 @@ from urllib.parse import urlsplit
from browser_cli import BrowserCLI
from browser_cli.mcp.naming import resolve_tool_prefix, tool_name
from browser_cli.mcp.serialization import structured
from browser_cli.mcp.targets import resolve_tab_id
ClientFactory = Callable[..., BrowserCLI]
@@ -93,27 +94,29 @@ def create_server(*, client_factory: ClientFactory = BrowserCLI, tool_prefix: st
@mcp.tool(name=tool_name("tabs_close", prefix))
def tabs_close(
tab_id: int,
tab_id: int | None = None,
browser: str | None = None,
remote: str | None = None,
key: str | None = None,
) -> dict[str, int]:
"""Close one tab by its current ID. This changes the user's real browser."""
closed = _client(client_factory, browser, remote, key).tabs.close(tab_id)
return {"closed": closed}
"""Close a tab, defaulting to the active tab. This changes the real browser."""
client = _client(client_factory, browser, remote, key)
target = resolve_tab_id(client, tab_id)
return {"closed": client.tabs.close(target), "tab_id": target}
@mcp.tool(name=tool_name("navigate", prefix))
def navigate(
tab_id: int,
url: str,
tab_id: int | None = None,
browser: str | None = None,
remote: str | None = None,
key: str | None = None,
) -> dict[str, Any]:
"""Navigate an existing tab to a URL and return a fresh tab snapshot."""
"""Navigate a tab to a URL, defaulting to the active tab, and return it."""
client = _client(client_factory, browser, remote, key)
client.nav.to(tab_id, url)
return structured(client.tabs.status(tab_id))
target = resolve_tab_id(client, tab_id)
client.nav.to(target, url)
return structured(client.tabs.status(target))
@mcp.tool(name=tool_name("page_info", prefix))
def page_info(