hanzo-tools-browser 0.5.7: fix CdpTool — implement register() (0.5.6 was DOA)

0.5.6 shipped CdpTool inheriting BaseTool but missing the required
`register()` abstract method, so any host that registered the tool
crashed with `TypeError: Can't instantiate abstract class CdpTool`.
The browser package never reached MCP startup, taking the whole hanzo
MCP server with it.

This commit adds CdpTool.register() with the cdp-specific param surface
(action / method / params / tab_id / target_browser / client_id / timeout)
matching the BrowserTool registration pattern.

Yanking 0.5.6 from PyPI alongside this release; 0.5.7 is the canonical
0.5.x for the three-tool surface.
This commit is contained in:
2026-06-10 10:24:33 -07:00
parent d6b31e8198
commit d6a01cea2a
2 changed files with 55 additions and 2 deletions
@@ -21,15 +21,25 @@ Example::
from __future__ import annotations
import json
import logging
import os
from typing import Any, Optional, Union
from typing import Any, Annotated, Literal, Optional, Union
from pydantic import Field
from mcp.server import FastMCP
from hanzo_tools.core import BaseTool
logger = logging.getLogger(__name__)
CdpAction = Annotated[
Literal["send", "tabs", "status", "list_browsers", "claim_browser", "release_browser"],
Field(description="CDP action"),
]
async def _dispatch_raw(
method: str,
params: Optional[dict] = None,
@@ -160,6 +170,49 @@ Use `playwright` for headless Playwright automation.
async def call(self, ctx, action: str = "send", **kwargs) -> dict[str, Any]:
return await self.execute(action=action, **kwargs)
def register(self, mcp_server: FastMCP) -> None:
"""Register the cdp tool with an MCP server."""
tool_instance = self
@mcp_server.tool(name=self.name, description=self.description)
async def cdp(
action: CdpAction = "send",
method: Annotated[
Optional[str],
Field(description="CDP method name (e.g. 'Page.navigate', 'Runtime.evaluate')"),
] = None,
params: Annotated[
Optional[dict],
Field(description="CDP method params"),
] = None,
tab_id: Annotated[
Optional[Union[str, int]],
Field(description="Target tab id (string or int)"),
] = None,
target_browser: Annotated[
Optional[str],
Field(description="Provider filter: firefox|chrome|safari|edge"),
] = None,
client_id: Annotated[
Optional[str],
Field(description="Specific extension client id"),
] = None,
timeout: Annotated[
Optional[float],
Field(description="Per-call timeout (seconds)"),
] = None,
) -> str:
result = await tool_instance.execute(
action=action,
method=method,
params=params,
tab_id=tab_id,
target_browser=target_browser,
client_id=client_id,
timeout=timeout,
)
return json.dumps(result, indent=2, default=str)
async def execute(
self,
action: str = "send",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "hanzo-tools-browser"
version = "0.5.6"
version = "0.5.7"
description = "Browser automation tools with ZAP-native extension routing — Python MCP hosts the ZAP server on an OS-assigned port and advertises via mDNS (HIP-0069). No node bridge, no port pool, no lockfile."
readme = "README.md"
requires-python = ">=3.12"