get_viewport_screenshot
Capture the current SketchUp viewport as a PNG for visual scene verification between steps. Optionally adjust view preset, style, or zoom extents before capture.
Instructions
Capture the current SketchUp viewport as a PNG and return it as an MCP Image.
Useful for letting Claude visually verify the scene between steps.
Parameters
max_size: largest side of the returned PNG (64..4096). Aspect ratio is taken from the current viewport; the smaller side is scaled proportionally.
view_preset: switch the camera to a standard view before snapping.
currentleaves the camera alone.zoom_extents: call view.zoom_extents before snapping.
style: temporarily flip a small set of rendering_options keys.
defaultleaves them alone.restore_view: when true (default), camera and rendering_options are snapshotted before mutation and restored after the snapshot, so the user's viewport is unchanged.
Note on operation order (Ruby handler): snapshot → preset → style →
zoom_extents → write_image → restore. Restore runs in an outer ensure
block, so an exception anywhere between snapshot and write_image still
leaves the viewport in its original state.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| max_size | No | ||
| view_preset | No | current | |
| zoom_extents | No | ||
| style | No | default | |
| restore_view | No |
Implementation Reference
- src/sketchup_mcp/tools.py:300-377 (handler)The actual handler function for the get_viewport_screenshot tool. It's an @mcp.tool()-decorated async function that accepts parameters (max_size, view_preset, zoom_extents, style, restore_view), delegates to _raw_call to communicate with the Ruby backend via JSON-RPC, extracts a base64-encoded PNG from the response, and returns a FastMCP Image object.
async def get_viewport_screenshot( ctx: Context, max_size: Annotated[int, Field(ge=64, le=4096)] = 800, view_preset: Literal[ "current", "front", "back", "left", "right", "top", "bottom", "iso", ] = "current", zoom_extents: bool = False, style: Literal["default", "shaded", "hidden_line", "wireframe"] = "default", restore_view: bool = True, ) -> Image: """Capture the current SketchUp viewport as a PNG and return it as an MCP Image. Useful for letting Claude visually verify the scene between steps. Parameters - max_size: largest side of the returned PNG (64..4096). Aspect ratio is taken from the current viewport; the smaller side is scaled proportionally. - view_preset: switch the camera to a standard view before snapping. ``current`` leaves the camera alone. - zoom_extents: call view.zoom_extents before snapping. - style: temporarily flip a small set of rendering_options keys. ``default`` leaves them alone. - restore_view: when true (default), camera and rendering_options are snapshotted before mutation and restored after the snapshot, so the user's viewport is unchanged. Note on operation order (Ruby handler): snapshot → preset → style → zoom_extents → write_image → restore. Restore runs in an outer ``ensure`` block, so an exception anywhere between snapshot and write_image still leaves the viewport in its original state. """ # Delegate connection + send_command to _raw_call so we don't duplicate # the transport logic of _call. _raw_call does NOT translate # ConnectionError (text-tools and Image-tools have divergent strategies), # so we convert here: there is no Image sentinel for "not connected", # so raise SketchUpError. See design §5.8 for the error-handling # asymmetry rationale. try: raw = await _raw_call( ctx, "get_viewport_screenshot", max_size=max_size, view_preset=view_preset, zoom_extents=zoom_extents, style=style, restore_view=restore_view, ) except ConnectionError as e: raise SketchUpError(-32000, f"SketchUp not running: {e}") from e # Ruby returns MCP-shaped {content: [{type: "text", text: JSON-blob}], ...}. # Extract the JSON blob and decode the base64 PNG into raw bytes. text: Optional[str] = None if isinstance(raw, dict): content = raw.get("content") if ( isinstance(content, list) and content and isinstance(content[0], dict) ): text = content[0].get("text") if not isinstance(text, str): raise SketchUpError( -32603, f"unexpected screenshot response shape: {raw!r}" ) try: payload = json.loads(text) except json.JSONDecodeError as e: raise SketchUpError(-32603, f"screenshot response not JSON: {e}") from e b64 = payload.get("png_base64") if not isinstance(b64, str): raise SketchUpError(-32603, "screenshot response missing png_base64") try: png_bytes = base64.b64decode(b64, validate=True) except (ValueError, base64.binascii.Error) as e: raise SketchUpError(-32603, f"png_base64 decode failed: {e}") from e return Image(data=png_bytes, format="png") - src/sketchup_mcp/tools.py:300-310 (schema)The function signature defines the input schema via Pydantic: max_size (int 64-4096), view_preset (Literal of camera positions), zoom_extents (bool), style (Literal of rendering options), restore_view (bool). The return type is Image.
async def get_viewport_screenshot( ctx: Context, max_size: Annotated[int, Field(ge=64, le=4096)] = 800, view_preset: Literal[ "current", "front", "back", "left", "right", "top", "bottom", "iso", ] = "current", zoom_extents: bool = False, style: Literal["default", "shaded", "hidden_line", "wireframe"] = "default", restore_view: bool = True, ) -> Image: - src/sketchup_mcp/tools.py:299-300 (registration)Registration via the @mcp.tool() decorator on line 299. The tools module is imported as a side-effect in app.py (line 51), which itself is imported by server.py.
@mcp.tool() async def get_viewport_screenshot( - src/sketchup_mcp/connection.py:43-53 (helper)The tool name "get_viewport_screenshot" is listed in _RETRY_SAFE_TOOLS in connection.py, marking it as read-only/idempotent so it can be safely retried on stale-socket errors.
_RETRY_SAFE_TOOLS: frozenset[str] = frozenset( { "get_model_info", "list_components", "get_component_info", "find_components", "list_layers", "get_selection", "get_viewport_screenshot", # read-only viewport capture; idempotent in # both restore_view modes (no document state changes) "get_version", # read-only diagnostic; no side effects