-
Notifications
You must be signed in to change notification settings - Fork 57
Description
There appears to be no way to have a clean screenshot of my phone. Every icon has a square drawn around it in the screenshot. Please consider adding this option to just allow clean screenshots, because sometimes I want to be able to give the screenshot to Claude Code and have it create a design system around it, for example. I have show layout bounds disabled on my phone.
This is what Claude Code says:
Unfortunately, the colored squares are added by the Android MCP tool itself - it's designed for automation/debugging and overlays UI element boundaries on the screenshot.
The Android MCP's State-Tool doesn't have an option to disable these overlays.
PS: Thanks so much for providing this MCP. I am suprised that Google doesn't have an official ADB mcp?
I inquired about the issue using DeepWiki. This is what it reported:
Verification: Claude Code is Correct
Yes, Claude Code's statement is TRUE. The colored squares are indeed added by the Android MCP tool itself, and there is currently no option to disable these overlays.
Here's what happens:
-
When you call the
State-Toolwithuse_vision=True, it callsmobile.get_state(use_vision=use_vision)1 -
The
get_state()method, whenuse_vision=True, always callstree.annotated_screenshot()which adds the colored rectangles 2 -
The
annotated_screenshot()method draws colored bounding boxes around every interactive element using random colors and numeric labels 3
Currently, your only options are:
use_vision=True→ Get annotated screenshot with colored boxesuse_vision=False→ Get NO screenshot at all
There is no way to get a clean, unannotated screenshot.
Proposed Solution
Add a new parameter annotate to control whether screenshots should have overlays. Here's an example pull request with the necessary code changes:
Example Pull Request
PR Title: Add option for clean screenshots without UI element annotations
PR Description:
Adds an annotate parameter to allow users to capture clean screenshots without colored bounding boxes and labels. This enables use cases where users want unmodified screenshots for design analysis or documentation.
Changes Required:
File 1: main.py
Modify the State-Tool to accept an annotate parameter:
@mcp.tool('State-Tool',description='Get the state of the device. Optionally includes visual screenshot when use_vision=True. Set annotate=False for clean screenshots without UI element overlays.')
def state_tool(use_vision:bool=False, annotate:bool=True):
mobile_state=mobile.get_state(use_vision=use_vision, annotate=annotate)
return [mobile_state.tree_state.to_string()]+([Image(data=mobile_state.screenshot,format='PNG')] if use_vision else [])File 2: src/mobile/__init__.py
Update get_state() to pass the annotate parameter:
def get_state(self, use_vision=False, annotate=True):
try:
tree = Tree(self)
tree_state = tree.get_state()
if use_vision:
nodes=tree_state.interactive_elements
if annotate:
screenshot_image = tree.annotated_screenshot(nodes=nodes, scale=1.0)
else:
screenshot_image = self.get_screenshot(scale=1.0)
screenshot = self.screenshot_in_bytes(screenshot_image)
else:
screenshot=None
return MobileState(tree_state=tree_state, screenshot=screenshot)
except Exception as e:
raise RuntimeError(f"Failed to get device state: {e}")Usage Examples:
# Get clean screenshot without annotations
state_tool(use_vision=True, annotate=False)
# Get annotated screenshot (default behavior, backward compatible)
state_tool(use_vision=True)
state_tool(use_vision=True, annotate=True)
# No screenshot (existing behavior)
state_tool(use_vision=False)Notes
- The solution maintains backward compatibility by defaulting
annotate=True, so existing code continues to work unchanged - The
get_screenshot()method already exists and captures clean screenshots 4 - The only blocker was that
get_state()had no conditional logic to choose between annotated and clean screenshots - The scale parameter should match (1.0) for consistency whether annotated or not
- This enables your use case of providing clean screenshots to Claude for design system analysis
Citations
File: main.py (L34-35)
mobile_state=mobile.get_state(use_vision=use_vision)
return [mobile_state.tree_state.to_string()]+([Image(data=mobile_state.screenshot,format='PNG')] if use_vision else [])File: src/mobile/init.py (L24-27)
if use_vision:
nodes=tree_state.interactive_elements
annotated_screenshot=tree.annotated_screenshot(nodes=nodes,scale=1.0)
screenshot=self.screenshot_in_bytes(annotated_screenshot)File: src/mobile/init.py (L34-43)
def get_screenshot(self,scale:float=0.7)->Image.Image:
try:
screenshot=self.device.screenshot()
if screenshot is None:
raise ValueError("Screenshot capture returned None.")
size=(screenshot.width*scale, screenshot.height*scale)
screenshot.thumbnail(size=size, resample=Image.Resampling.LANCZOS)
return screenshot
except Exception as e:
raise RuntimeError(f"Failed to get screenshot: {e}")File: src/tree/init.py (L73-85)
def draw_annotation(label, node: ElementNode):
bounding_box = node.bounding_box
color = get_random_color()
# Scale and pad the bounding box also clip the bounding box
adjusted_box = (
int(bounding_box.x1 * scale) + padding,
int(bounding_box.y1 * scale) + padding,
int(bounding_box.x2 * scale) + padding,
int(bounding_box.y2 * scale) + padding
)
# Draw bounding box
draw.rectangle(adjusted_box, outline=color, width=2)